97

How can I verify whether a running process will catch a signal, or ignore it, or block it? Ideally I'd like to see a list of signals, or at least not have to actually send the signal to check.

Jander
  • 16,682

9 Answers9

140

Under Linux, you can find the PID of your process, then look at /proc/$PID/status. It contains lines describing which signals are blocked (SigBlk), ignored (SigIgn), or caught (SigCgt).

# cat /proc/1/status
...
SigBlk: 0000000000000000
SigIgn: fffffffe57f0d8fc
SigCgt: 00000000280b2603
...

The number to the right is a bitmask. If you convert it from hex to binary, each 1-bit represents a caught signal, counting from right to left starting with 1. So by interpreting the SigCgt line, we can see that my init process is catching the following signals:

00000000280b2603 ==> 101000000010110010011000000011
                     | |       | ||  |  ||       |`->  1 = SIGHUP
                     | |       | ||  |  ||       `-->  2 = SIGINT
                     | |       | ||  |  |`----------> 10 = SIGUSR1
                     | |       | ||  |  `-----------> 11 = SIGSEGV
                     | |       | ||  `--------------> 14 = SIGALRM
                     | |       | |`-----------------> 17 = SIGCHLD
                     | |       | `------------------> 18 = SIGCONT
                     | |       `--------------------> 20 = SIGTSTP
                     | `----------------------------> 28 = SIGWINCH
                     `------------------------------> 30 = SIGPWR

(I found the number-to-name mapping by running kill -l from bash.)

EDIT: And by popular demand, a script, in POSIX sh.

sigparse () {
    i=0
    # bits="$(printf "16i 2o %X p" "0x$1" | dc)" # variant for busybox
    bits="$(printf "ibase=16; obase=2; %X\n" "0x$1" | bc)"
    while [ -n "$bits" ] ; do
        i="$(expr "$i" + 1)"
        case "$bits" in
            *1) printf " %s(%s)" "$(kill -l "$i")" "$i" ;;
        esac
        bits="${bits%?}"
    done
}

grep "^Sig...:" "/proc/$1/status" | while read a b ; do
        printf "%s%s\n" "$a" "$(sigparse "$b")"
    done # | fmt -t  # uncomment for pretty-printing
Jander
  • 16,682
  • 2
    If a signal is listed under SigBlk does it also appear in SigCgt? Because by blocking it, it just means the signal will be resent a little bit later right and the needs to be caught? – CMCDragonkai May 29 '15 at 07:28
  • No, you can block a signal without being ready to catch it. If you don't catch a signal, a default action will happen depending on the signal (usually process termination). If you want more detail you ought to open a question. – Jander May 29 '15 at 22:21
  • What's the use of a POSIX version of a script reading from /proc? It's only going to work on Linux... And local isn't POSIX. Well, it kinda is, but its effect is "unspecified". – Kusalananda Jan 07 '17 at 19:42
  • 3
    @Kusalananda: Linux doesn't imply Bash -- for example, small embedded platforms often use Busybox -- but POSIX compliance is a near guarantee for any modern /bin/sh. You're right about local; I'll clean that up. – Jander Jan 08 '17 at 03:52
  • @Jander Fair point. I confess to making a hasty assumption regarding Bash and Linux. – Kusalananda Jan 08 '17 at 08:48
  • Where exactly in the standard does it say printf accepts hexadecimal numbers in 0xHEX form? –  Apr 12 '20 at 07:17
24

On Solaris, run psig on the process id to get a list of signals and how they'll be handled.

For instance:

bash-4.2$ psig $$
11088:  bash
HUP     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
INT     caught  sigint_sighandler   0
QUIT    ignored
ILL     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
TRAP    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
ABRT    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
EMT     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
FPE     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
KILL    default
BUS     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
SEGV    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
SYS     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
PIPE    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
ALRM    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
TERM    ignored
USR1    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
USR2    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
CLD     blocked,caught  0x4898e8    RESTART
PWR     default
WINCH   caught  sigwinch_sighandler 0
[...]

which shows that SIGHUP, SIGILL, etc. will all be caught by the same signal handler function termsig_sighandler, which will be run without using any of the flags that could be set via sigaction, and all the signals that will be temporarily masked while the signal handler is running (in this case all the ones using the same signal handler, so it's not reentered while already running). You can also see that SIGQUIT & SIGTERM will be ignored, SIGKILL & SIGPWR use the system default signal actions, and SIGCLD specifies the RESTART flag, so if its signal handler interrupts a system call, the syscall will be restarted.

alanc
  • 2,994
8

(This answer is similar to @user18096's answer, in that it creates a script around @Jander's answer.)

I've written a psig script to take a PID (or all PIDs) and create human-readable output from the signal masks in /proc/<PID>/status.

Example output:

% ./psig -a
[     1] Signals Queued: 8/773737
[     1] Signals Pending:
[     1] Signals Pending (Shared):
[     1] Signals Blocked:
[     1] Signals Ignored: SIGPIPE
[     1] Signals Caught: SIGHUP,SIGINT,SIGABRT,SIGUSR1,SIGSEGV,SIGALRM,SIGTERM,SIGCHLD,SIGPWR
...
[ 31001] Signals Queued: 0/773737
[ 31001] Signals Pending:
[ 31001] Signals Pending (Shared):
[ 31001] Signals Blocked: SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,SIGABRT,SIGBUS,SIGFPE,SIGUSR1,SIGUSR2,SIGPIPE,SIGALRM,SIGTERM,SIGSTKFLT,SIGCHLD,SIGCONT,SIGTSTP,SIGTTIN,SIGTTOU,SIGURG,SIGXCPU,SIGXFSZ,SIGPROF,SIGWINCH,SIGIO,SIGPWR,SIGSYS,SIGRTMIN,SIGRTMIN+1,SIGRTMIN+2,SIGRTMIN+3,SIGRTMIN+4,SIGRTMIN+5,SIGRTMIN+6,SIGRTMIN+7,SIGRTMIN+8,SIGRTMIN+9,SIGRTMIN+10,SIGRTMIN+11,SIGRTMIN+12,SIGRTMIN+13,SIGRTMIN+14,SIGRTMIN+15,SIGRTMAX-14,SIGRTMAX-13,SIGRTMAX-12,SIGRTMAX-11,SIGRTMAX-10,SIGRTMAX-9,SIGRTMAX-8,SIGRTMAX-7,SIGRTMAX-6,SIGRTMAX-5,SIGRTMAX-4,SIGRTMAX-3,SIGRTMAX-2,SIGRTMAX-1,SIGRTMAX
[ 31001] Signals Ignored: SIGHUP,SIGINT,SIGQUIT,SIGPIPE,SIGXFSZ
[ 31001] Signals Caught: SIGBUS,SIGUSR1,SIGSEGV,SIGUSR2,SIGALRM,SIGTERM,SIGVTALRM

Caveats:

  • This is a Linux specific answer.
  • Might need a relatively new Python version to run the script, it uses with and OrderedDict.
2

Use this(link broken) this library to get infos about the jobs, which are running.

There is a special field in the struct Job for the signals, called sigCgt

You may use something like this:

#include"read_proc.h"
int main(void)
{
    struct Root * rt=read_proc();
    struct Job * jb=rt->first->job;
    printf("%ull\n",jb->sigCgt);
    return 0;
}
2

I keep coming back to @Jander's pretty answer hoping for a copy-and-paste decoder when faced with the like of:

user@machine:~$ grep Sig...: /proc/18475/status
SigPnd: 0000000000000000
SigBlk: fffffffe7dfbfaff
SigIgn: 0000000000001000
SigCgt: 0000000182006e47
user@machine:~$ 

Guess I'll have to knock something up... say:

user@machine:~$ ruby -wn - /proc/18475/status <<'EOF'
if $_.match(/Sig(Pnd|Blk|Ign|Cgt):\s([0-9a-f]{16})/) == nil
  next
end
field = $1
mask = $2.to_i(16)
names = []
Signal.list().each_pair() {
  |name, number|
  if number == 0
    # "EXIT" => 0
    next
  end
  if (mask & (1 << (number - 1))) == 0
    next
  end
  names << name
}
puts("Sig#{field}: #{names.join(" | ")}")
EOF
SigPnd: 
SigBlk: HUP | INT | QUIT | ILL | TRAP | IOT | ABRT | FPE | BUS | SYS | PIPE | ALRM | TERM | URG | TSTP | CONT | CHLD | CLD | TTIN | TTOU | IO | XCPU | XFSZ | PROF | WINCH | USR1 | USR2 | PWR | POLL
SigIgn: PIPE
SigCgt: HUP | INT | QUIT | BUS | SEGV | ALRM | TERM | VTALRM | USR1 | USR2
user@machine:~$ 

I wanted it to be somewhat legible, but that's made it a bit clumsier to invoke than I'd like, so, thanks to @alanc's suggestion, I'll save it as ~/bin/psig.

2

On FreeBSD, use procstat -i <PID> to see which signals are ignored by the process. Similarly, procstat -j <PID> to see which signals are blocked by the process threads. Both commands show if a signal is pending.

Sample output:

$ procstat -i 38540 PID COMM SIG FLAGS 38540 nsulfd HUP -I- 38540 nsulfd INT -I- 38540 nsulfd QUIT -I- 38540 nsulfd ILL --- 38540 nsulfd TRAP --- ...

$ procstat -j 38540 PID TID COMM SIG FLAGS 38540 101220 nsulfd HUP -- 38540 101220 nsulfd INT -- 38540 101220 nsulfd QUIT -B 38540 101220 nsulfd ILL -- 38540 101220 nsulfd TRAP -- ...

See procstat(1).

Deepak
  • 121
1

I have written a zsh function, which should be highly portable, since the only dependencies are awk and column for the fancy output:

psig()

psig()
{
    declare -a pid_signal_array
    pid_signal_array[1]="SIGHUP"
    pid_signal_array[2]="SIGINT"
    pid_signal_array[3]="SIGQUIT"
    pid_signal_array[4]="SIGKILL"
    pid_signal_array[5]="SIGTRAP"
    pid_signal_array[6]="SIGABRT"
    pid_signal_array[7]="SIGBUS"
    pid_signal_array[8]="SIGFPE"
    pid_signal_array[9]="SIGKILL"
    pid_signal_array[10]="SIGUSR1"
    pid_signal_array[11]="SIGSEGV"
    pid_signal_array[12]="SIGUSR2"
    pid_signal_array[13]="SIGPIPE"
    pid_signal_array[14]="SIGALRM"
    pid_signal_array[15]="SIGTERM"
    pid_signal_array[16]="SIGSTKFLT"
    pid_signal_array[17]="SIGCHLD"
    pid_signal_array[18]="SIGCONT"
    pid_signal_array[19]="SIGSTOP"
    pid_signal_array[20]="SIGTSTP"
    pid_signal_array[21]="SIGTTIN"
    pid_signal_array[22]="SIGTTOU"
    pid_signal_array[23]="SIGURG"
    pid_signal_array[24]="SIGXCPU"
    pid_signal_array[25]="SIGXFSZ"
    pid_signal_array[26]="SIGVTALRM"
    pid_signal_array[27]="SIGPROF"
    pid_signal_array[28]="SIGWINCH"
    pid_signal_array[29]="SIGIO"
    pid_signal_array[30]="SIGPWR"
    pid_signal_array[31]="SIGSYS"
    # not defined
    #pid_signal_array[32]=""
    #pid_signal_array[33]=""
    pid_signal_array[34]="SIGRTMIN"
    pid_signal_array[35]="SIGRTMIN+1"
    pid_signal_array[36]="SIGRTMIN+2"
    pid_signal_array[37]="SIGRTMIN+3"
    pid_signal_array[38]="SIGRTMIN+4"
    pid_signal_array[39]="SIGRTMIN+5"
    pid_signal_array[40]="SIGRTMIN+6"
    pid_signal_array[41]="SIGRTMIN+7"
    pid_signal_array[42]="SIGRTMIN+8"
    pid_signal_array[43]="SIGRTMIN+9"
    pid_signal_array[44]="SIGRTMIN+10"
    pid_signal_array[45]="SIGRTMIN+11"
    pid_signal_array[46]="SIGRTMIN+12"
    pid_signal_array[47]="SIGRTMIN+13"
    pid_signal_array[48]="SIGRTMIN+14"
    pid_signal_array[49]="SIGRTMIN+15"
    pid_signal_array[50]="SIGRTMAX-14"
    pid_signal_array[51]="SIGRTMAX-13"
    pid_signal_array[52]="SIGRTMAX-12"
    pid_signal_array[53]="SIGRTMAX-11"
    pid_signal_array[54]="SIGRTMAX-10"
    pid_signal_array[55]="SIGRTMAX-9"
    pid_signal_array[56]="SIGRTMAX-8"
    pid_signal_array[57]="SIGRTMAX-7"
    pid_signal_array[58]="SIGRTMAX-6"
    pid_signal_array[59]="SIGRTMAX-5"
    pid_signal_array[60]="SIGRTMAX-4"
    pid_signal_array[61]="SIGRTMAX-3"
    pid_signal_array[62]="SIGRTMAX-2"
    pid_signal_array[63]="SIGRTMAX-1"
    pid_signal_array[64]="SIGRTMAX"
    declare -A hex_value_array
    local hex_value_array["0"]="0"
    local hex_value_array["1"]="1"
    local hex_value_array["2"]="2"
    local hex_value_array["3"]="3"
    local hex_value_array["4"]="4"
    local hex_value_array["5"]="5"
    local hex_value_array["6"]="6"
    local hex_value_array["7"]="7"
    local hex_value_array["8"]="8"
    local hex_value_array["9"]="9"
    local hex_value_array["a"]="10"
    local hex_value_array["b"]="11"
    local hex_value_array["c"]="12"
    local hex_value_array["d"]="13"
    local hex_value_array["e"]="14"
    local hex_value_array["f"]="15"
    declare -a bin_value_4bit_array=({0..1}{0..1}{0..1}{0..1})
    declare -A pid_signal_name_array
    local pid_signal_name_array["SigPnd:"]="Signals pending (thread):"
    local pid_signal_name_array["ShdPnd:"]="Signals pending (process):"
    local pid_signal_name_array["SigBlk:"]="Signals blocked:"
    local pid_signal_name_array["SigIgn:"]="Signals ignored:"
    local pid_signal_name_array["SigCgt:"]="Signals caught:"
declare -a pid_array=(&quot;${@}&quot;)
for pid in &quot;${pid_array[@]}&quot;
do
    local pid_directory_path=&quot;/proc/${pid}&quot;
    local pid_status_file=&quot;status&quot;
    local pid_status=$(&lt; &quot;${pid_directory_path}/${pid_status_file}&quot;)
    declare -a pid_signal_bin_value_4bit_array
    declare -a pid_signal_bin_value_1bit_array
    unset hex_position
    unset hex_value
    unset binary_position
    unset binary_value
    local hex_position
    local hex_value
    local binary_position
    local binary_value

    echo &quot;&quot;
    echo -n &quot;PID: ${pid}&quot;
    for pid_signal_name in &quot;${(k)pid_signal_name_array[@]}&quot;
    do
        local pid_signal_hex_value=$(echo &quot;${pid_status}&quot; | awk --assign=&quot;pid_signal_name=${pid_signal_name}&quot; '$0 ~ pid_signal_name { print $2 }')
        declare -a pid_signal_hex_value_delimited_array

        # refactor me: create function &quot;hexToBin()&quot;

        # split hexadecimal string per character
        # from: 0000000180004a03
        # to:   0 0 0 0 0 0 0 1 8 0 0 0 4 a 0 3
        unset pid_signal_hex_value_delimited_array
        for hex_position in {0..&quot;${#pid_signal_hex_value}&quot;}
        do
            pid_signal_hex_value_delimited_array+=(&quot;${pid_signal_hex_value:${hex_position}:1}&quot;)
        done

        # convert hexadecimal to binary per character
        # from: 0    0    0    0    0    0    0    1    8    0    0    0    4    a    0    3
        # to:   0000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 0100 1010 0000 0011
        unset pid_signal_bin_value_4bit_array
        for hex_value in &quot;${pid_signal_hex_value_delimited_array[@]}&quot;
        do
            if [[ &quot;${hex_value}&quot; =~ ^[0-9]$ ]]
            then
                pid_signal_bin_value_4bit_array+=&quot;${bin_value_4bit_array[${hex_value}+1]} &quot;
            elif [[ &quot;${hex_value}&quot; =~ ^[a-fA-F]$ ]]
            then
                pid_signal_bin_value_4bit_array+=&quot;${bin_value_4bit_array[hex_value_array[${hex_value}]+1]} &quot;
            fi
        done

        # concatenate binary string and split string per character
        # from: 0000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 0100 1010 0000 0011
        # to:   0000000000000000000000000000000110000000000000000100101000000011
        # to:   0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1 1
        pid_signal_bin_value_concatenated=&quot;${pid_signal_bin_value_4bit_array[@]// /}&quot;
        unset pid_signal_bin_value_1bit_array
        for binary_position in {0..&quot;$(( ${#pid_signal_bin_value_concatenated} - 1 ))&quot;}
        do
            pid_signal_bin_value_1bit_array+=(&quot;${pid_signal_bin_value_concatenated:${binary_position}:1}&quot;)
        done

        # convert binary to signal name per character
        # from: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1 1
        # to:   Signal &lt;signal_number&gt;: &lt;signal_name&gt;
        local binary_array_index=&quot;${#pid_signal_bin_value_concatenated}&quot;

        echo &quot;&quot;
        echo &quot;${pid_signal_name_array[${pid_signal_name}]}&quot;
        echo &quot;${pid_signal_name_array[${pid_signal_name}]//[a-zA-Z :()]/-}&quot;
        for binary_value in &quot;${pid_signal_bin_value_1bit_array[@]}&quot;
        do
            # signal &quot;32&quot; and &quot;33&quot; are undefined
            if [[ &quot;${binary_array_index}&quot; == &quot;32&quot; || &quot;${binary_array_index}&quot; == &quot;33&quot; ]]
            then
                (( binary_array_index-- ))
                continue
            elif [[ &quot;${binary_value}&quot; == &quot;0&quot; ]]
            then
                (( binary_array_index-- ))
                continue
            elif [[ &quot;${binary_value}&quot; == &quot;1&quot; ]]
            then
                echo &quot;Signal ${binary_array_index}: ${pid_signal_array[${binary_array_index}]}&quot;
            fi

            (( binary_array_index-- ))
        done

        # output results, if there is any signal. also output results, if signal &quot;32&quot; and &quot;33&quot; are set to &quot;1&quot;, which actually does not make any sense.
        if [[ &quot;${pid_signal_bin_value_concatenated}&quot; == *&quot;1&quot;* ]]
        then
            echo -e &quot;Hexadecimal: ${pid_signal_hex_value_delimited_array[@]}\nBinary: ${pid_signal_bin_value_4bit_array[@]}&quot; | column --table
        else
            echo &quot;No signals found.&quot;
        fi
    done
done

}

% psig $$
SigCgt
Signal 28: SIGWINCH
Signal 17: SIGCHLD
Signal 14: SIGALRM
Signal 13: SIGPIPE
Signal 2: SIGINT
Signal 1: SIGHUP

Hexadecimal:  0     0     0     0     0     0     0     0     0     8     0     1     3     0     0     3
Binary:       0000  0000  0000  0000  0000  0000  0000  0000  0000  1000  0000  0001  0011  0000  0000  0011

It is still in development and only covers SigCgt for now. I am going to port it to Bash and put it into its own repository.

I ported it to Bash and it supports all signal types: https://codeberg.org/keks24/psig

psig

#!/bin/bash
#############################################################################
# Copyright 2021 Ramon Fischer                                              #
#                                                                           #
# Licensed under the Apache License, Version 2.0 (the "License");           #
# you may not use this file except in compliance with the License.          #
# You may obtain a copy of the License at                                   #
#                                                                           #
#     http://www.apache.org/licenses/LICENSE-2.0                            #
#                                                                           #
# Unless required by applicable law or agreed to in writing, software       #
# distributed under the License is distributed on an "AS IS" BASIS,         #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  #
# See the License for the specific language governing permissions and       #
# limitations under the License.                                            #
#############################################################################

define global variables

declare -a pid_signal_array pid_signal_array[1]="SIGHUP" pid_signal_array[2]="SIGINT" pid_signal_array[3]="SIGQUIT" pid_signal_array[4]="SIGKILL" pid_signal_array[5]="SIGTRAP" pid_signal_array[6]="SIGABRT" pid_signal_array[7]="SIGBUS" pid_signal_array[8]="SIGFPE" pid_signal_array[9]="SIGKILL" pid_signal_array[10]="SIGUSR1" pid_signal_array[11]="SIGSEGV" pid_signal_array[12]="SIGUSR2" pid_signal_array[13]="SIGPIPE" pid_signal_array[14]="SIGALRM" pid_signal_array[15]="SIGTERM" pid_signal_array[16]="SIGSTKFLT" pid_signal_array[17]="SIGCHLD" pid_signal_array[18]="SIGCONT" pid_signal_array[19]="SIGSTOP" pid_signal_array[20]="SIGTSTP" pid_signal_array[21]="SIGTTIN" pid_signal_array[22]="SIGTTOU" pid_signal_array[23]="SIGURG" pid_signal_array[24]="SIGXCPU" pid_signal_array[25]="SIGXFSZ" pid_signal_array[26]="SIGVTALRM" pid_signal_array[27]="SIGPROF" pid_signal_array[28]="SIGWINCH" pid_signal_array[29]="SIGIO" pid_signal_array[30]="SIGPWR" pid_signal_array[31]="SIGSYS"

not defined

#pid_signal_array[32]="" #pid_signal_array[33]="" pid_signal_array[34]="SIGRTMIN" pid_signal_array[35]="SIGRTMIN+1" pid_signal_array[36]="SIGRTMIN+2" pid_signal_array[37]="SIGRTMIN+3" pid_signal_array[38]="SIGRTMIN+4" pid_signal_array[39]="SIGRTMIN+5" pid_signal_array[40]="SIGRTMIN+6" pid_signal_array[41]="SIGRTMIN+7" pid_signal_array[42]="SIGRTMIN+8" pid_signal_array[43]="SIGRTMIN+9" pid_signal_array[44]="SIGRTMIN+10" pid_signal_array[45]="SIGRTMIN+11" pid_signal_array[46]="SIGRTMIN+12" pid_signal_array[47]="SIGRTMIN+13" pid_signal_array[48]="SIGRTMIN+14" pid_signal_array[49]="SIGRTMIN+15" pid_signal_array[50]="SIGRTMAX-14" pid_signal_array[51]="SIGRTMAX-13" pid_signal_array[52]="SIGRTMAX-12" pid_signal_array[53]="SIGRTMAX-11" pid_signal_array[54]="SIGRTMAX-10" pid_signal_array[55]="SIGRTMAX-9" pid_signal_array[56]="SIGRTMAX-8" pid_signal_array[57]="SIGRTMAX-7" pid_signal_array[58]="SIGRTMAX-6" pid_signal_array[59]="SIGRTMAX-5" pid_signal_array[60]="SIGRTMAX-4" pid_signal_array[61]="SIGRTMAX-3" pid_signal_array[62]="SIGRTMAX-2" pid_signal_array[63]="SIGRTMAX-1" pid_signal_array[64]="SIGRTMAX" declare -A hex_value_array hex_value_array["0"]="0" hex_value_array["1"]="1" hex_value_array["2"]="2" hex_value_array["3"]="3" hex_value_array["4"]="4" hex_value_array["5"]="5" hex_value_array["6"]="6" hex_value_array["7"]="7" hex_value_array["8"]="8" hex_value_array["9"]="9" hex_value_array["a"]="10" hex_value_array["b"]="11" hex_value_array["c"]="12" hex_value_array["d"]="13" hex_value_array["e"]="14" hex_value_array["f"]="15"

array index (decimal) points to corresponding binary value

declare -a bin_value_4bit_array=({0..1}{0..1}{0..1}{0..1}) declare -A pid_signal_name_array pid_signal_name_array["SigPnd:"]="Signals pending (thread):" pid_signal_name_array["ShdPnd:"]="Signals pending (process):" pid_signal_name_array["SigBlk:"]="Signals blocked:" pid_signal_name_array["SigIgn:"]="Signals ignored:" pid_signal_name_array["SigCgt:"]="Signals caught:" underline_regex="[a-zA-Z:() ]"

main() { declare -a pid_array=("${@}") for pid in "${pid_array[@]}" do local pid_directory_path="/proc/${pid}" local pid_status_file="status" local pid_status=$(< "${pid_directory_path}/${pid_status_file}") local pid_name=$(echo "${pid_status}" | /usr/bin/awk --field-separator="Name:\t" '/Name:/ { print $2 }') declare -a pid_signal_bin_value_4bit_array declare -a pid_signal_bin_value_1bit_array local hex_position local hex_value local binary_position local binary_value

    echo &quot;&quot;
    echo -e &quot;PID: ${pid}&quot;
    echo -n &quot;Name: ${pid_name}&quot;
    for pid_signal_name in &quot;${!pid_signal_name_array[@]}&quot;
    do
        local pid_signal_hex_value=$(echo &quot;${pid_status}&quot; | /usr/bin/awk --assign=&quot;pid_signal_name=${pid_signal_name}&quot; '$0 ~ pid_signal_name { print $2 }')
        declare -a pid_signal_hex_value_delimited_array

        # refactor me: create function &quot;hexToBin()&quot;

        # split hexadecimal string per character
        # from: 0000000180004a03
        # to:   0 0 0 0 0 0 0 1 8 0 0 0 4 a 0 3
        unset pid_signal_hex_value_delimited_array
        for hex_position in $(eval echo &quot;{0..${#pid_signal_hex_value}}&quot;)
        do
            pid_signal_hex_value_delimited_array+=(&quot;${pid_signal_hex_value:${hex_position}:1}&quot;)
        done

        # convert hexadecimal to binary per character
        # from: 0    0    0    0    0    0    0    1    8    0    0    0    4    a    0    3
        # to:   0000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 0100 1010 0000 0011
        unset pid_signal_bin_value_4bit_array
        for hex_value in &quot;${pid_signal_hex_value_delimited_array[@]}&quot;
        do
            if [[ &quot;${hex_value}&quot; =~ ^[0-9]$ ]]
            then
                pid_signal_bin_value_4bit_array+=&quot;${bin_value_4bit_array[${hex_value}]} &quot;
            elif [[ &quot;${hex_value}&quot; =~ ^[a-fA-F]$ ]]
            then
                pid_signal_bin_value_4bit_array+=&quot;${bin_value_4bit_array[hex_value_array[${hex_value}]]} &quot;
            fi
        done

        # concatenate binary string and split string per character
        # from: 0000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 0100 1010 0000 0011
        # to:   0000000000000000000000000000000110000000000000000100101000000011
        # to:   0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1 1
        pid_signal_bin_value_concatenated=&quot;${pid_signal_bin_value_4bit_array[@]// /}&quot;
        unset pid_signal_bin_value_1bit_array
        for binary_position in $(eval echo &quot;{0..$(( ${#pid_signal_bin_value_concatenated} ))}&quot;)
        do
            pid_signal_bin_value_1bit_array+=(&quot;${pid_signal_bin_value_concatenated:${binary_position}:1}&quot;)
        done

        # convert binary to signal name per character
        # from: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1 1
        # to:   Signal &lt;signal_number&gt;: &lt;signal_name&gt;
        local binary_array_index=&quot;${#pid_signal_bin_value_concatenated}&quot;
        echo &quot;&quot;
        echo &quot;${pid_signal_name_array[${pid_signal_name}]}&quot;
        echo &quot;${pid_signal_name_array[${pid_signal_name}]//${underline_regex}/-}&quot;
        for binary_value in &quot;${pid_signal_bin_value_1bit_array[@]}&quot;
        do
            # signal &quot;32&quot; and &quot;33&quot; are undefined
            if [[ &quot;${binary_array_index}&quot; == &quot;32&quot; || &quot;${binary_array_index}&quot; == &quot;33&quot; ]]
            then
                (( binary_array_index-- ))
                continue
            elif [[ &quot;${binary_value}&quot; == &quot;0&quot; ]]
            then
                (( binary_array_index-- ))
                continue
            elif [[ &quot;${binary_value}&quot; == &quot;1&quot; ]]
            then
                echo &quot;Signal ${binary_array_index}: ${pid_signal_array[${binary_array_index}]}&quot;
            fi

            (( binary_array_index-- ))
        done

        # output results, if there is any signal. also output results, if signal &quot;32&quot; and &quot;33&quot; are set to &quot;1&quot;, which actually does not make any sense.
        if [[ &quot;${pid_signal_bin_value_concatenated}&quot; == *&quot;1&quot;* ]]
        then
            echo -e &quot;Hexadecimal: ${pid_signal_hex_value_delimited_array[@]}\nBinary: ${pid_signal_bin_value_4bit_array[@]}&quot; | column --table
        else
            echo &quot;No signals found.&quot;
        fi
    done
done

}

main "${@}"

$ psig $$

PID: 10392
Name: zsh
Signals caught:
---------------
Signal 28: SIGWINCH
Signal 17: SIGCHLD
Signal 14: SIGALRM
Signal 13: SIGPIPE
Signal 2: SIGINT
Signal 1: SIGHUP
Hexadecimal:  0     0     0     0     0     0     0     0     0     8     0     1     3     0     0     3
Binary:       0000  0000  0000  0000  0000  0000  0000  0000  0000  1000  0000  0001  0011  0000  0000  0011

Signals pending (process):
--------------------------
No signals found.

Signals pending (thread):
-------------------------
No signals found.

Signals blocked:
----------------
Signal 2: SIGINT
Hexadecimal:  0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     2
Binary:       0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0010

Signals ignored:
----------------
Signal 22: SIGTTOU
Signal 21: SIGTTIN
Signal 20: SIGTSTP
Signal 15: SIGTERM
Hexadecimal:  0     0     0     0     0     0     0     0     0     0     3     8     4     0     0     0
Binary:       0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0011  1000  0100  0000  0000  0000
0

I created a small script in bash to see all those signals for a process:

[mvutcovi@mvutcovi-lap2 ~]$ cat signals.sh 
#read -p "PID=" pid
pid=$1
cat /proc/$pid/status|egrep '(Sig|Shd)(Pnd|Blk|Ign|Cgt)'|while read name mask;do
    bin=$(echo "ibase=16; obase=2; ${mask^^*}"|bc)
    echo -n "$name $mask $bin "
    i=1
    while [[ $bin -ne 0 ]];do
        if [[ ${bin:(-1)} -eq 1 ]];then
            kill -l $i | tr '\n' ' '
        fi
        bin=${bin::-1}
        set $((i++))
    done
    echo
done
# vim:et:sw=4:ts=4:sts=4:
[mvutcovi@mvutcovi-lap2 ~]$ sleep 1234 &./signals.sh $(pgrep -f "sleep .*1234");pkill sleep
[1] 2613776
SigPnd: 0000000000000000 0 
ShdPnd: 0000000000000000 0 
SigBlk: 0000000000000000 0 
SigIgn: 0000000000000000 0 
SigCgt: 0000000000000000 0 
[1]+  Terminated              sleep 1234
[mvutcovi@mvutcovi-lap2 ~]$ nohup sleep 1234 &./signals.sh $(pgrep -f "sleep .*1234");pkill sleep
[1] 2613812
nohup: ignoring input and appending output to 'nohup.out'
SigPnd: 0000000000000000 0 
ShdPnd: 0000000000000000 0 
SigBlk: 0000000000000000 0 
SigIgn: 0000000000000001 1 HUP 
SigCgt: 0000000000000000 0 
[1]+  Terminated              nohup sleep 1234
[mvutcovi@mvutcovi-lap2 ~]$ 
Mircea Vutcovici
  • 1,834
  • 14
  • 9
0

Awesome work on the bash scripts, thanks for sharing! In the bash psig.sh I had to change line 202 for it to work on Ubuntu 20.04. --table seems to have been deprecated so I changed it to -t.

before

~/bin$ psig.sh 2625

PID: 2625 Name: file.so Signals caught:


Signal 15: SIGTERM Signal 11: SIGSEGV Signal 8: SIGFPE Signal 7: SIGBUS Signal 6: SIGABRT Signal 4: SIGKILL Signal 3: SIGQUIT Signal 2: SIGINT column: invalid option -- '-' usage: column [-txne] [-c columns] [-s sep] [file ...]

after

:~/bin$ psig.sh 2625

PID: 2625 Name: file.so Signals caught:


Signal 15: SIGTERM Signal 11: SIGSEGV Signal 8: SIGFPE Signal 7: SIGBUS Signal 6: SIGABRT Signal 4: SIGKILL Signal 3: SIGQUIT Signal 2: SIGINT Hexadecimal: 0 0 0 0 0 0 0 1 8 0 0 0 4 4 e e Binary: 0000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 0100 0100 1110 1110

JamesL
  • 1,270
  • 1
  • 14
  • 19