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.

0

9 Answers 9

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
6
  • 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? May 29, 2015 at 7: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, 2015 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 7, 2017 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 8, 2017 at 3:52
  • @Jander Fair point. I confess to making a hasty assumption regarding Bash and Linux.
    – Kusalananda
    Jan 8, 2017 at 8:48
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.

1
  • Awesome! I was hoping someone would add a non-Linux answer.
    – Jander
    Aug 5, 2013 at 2:14
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

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

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'd love to but the link is broken. Jan 6, 2017 at 15:32
  • 1
    @MichaelFox see my edit. The user has deleted his account. The new link points to the same project Jan 7, 2017 at 17:34
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).

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=("${@}")
    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}")
        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 ""
        echo -n "PID: ${pid}"
        for pid_signal_name in "${(k)pid_signal_name_array[@]}"
        do
            local pid_signal_hex_value=$(echo "${pid_status}" | awk --assign="pid_signal_name=${pid_signal_name}" '$0 ~ pid_signal_name { print $2 }')
            declare -a pid_signal_hex_value_delimited_array

            # refactor me: create function "hexToBin()"

            # 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.."${#pid_signal_hex_value}"}
            do
                pid_signal_hex_value_delimited_array+=("${pid_signal_hex_value:${hex_position}:1}")
            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 "${pid_signal_hex_value_delimited_array[@]}"
            do
                if [[ "${hex_value}" =~ ^[0-9]$ ]]
                then
                    pid_signal_bin_value_4bit_array+="${bin_value_4bit_array[${hex_value}+1]} "
                elif [[ "${hex_value}" =~ ^[a-fA-F]$ ]]
                then
                    pid_signal_bin_value_4bit_array+="${bin_value_4bit_array[hex_value_array[${hex_value}]+1]} "
                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="${pid_signal_bin_value_4bit_array[@]// /}"
            unset pid_signal_bin_value_1bit_array
            for binary_position in {0.."$(( ${#pid_signal_bin_value_concatenated} - 1 ))"}
            do
                pid_signal_bin_value_1bit_array+=("${pid_signal_bin_value_concatenated:${binary_position}:1}")
            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 <signal_number>: <signal_name>
            local binary_array_index="${#pid_signal_bin_value_concatenated}"

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

                (( binary_array_index-- ))
            done

            # output results, if there is any signal. also output results, if signal "32" and "33" are set to "1", which actually does not make any sense.
            if [[ "${pid_signal_bin_value_concatenated}" == *"1"* ]]
            then
                echo -e "Hexadecimal: ${pid_signal_hex_value_delimited_array[@]}\nBinary: ${pid_signal_bin_value_4bit_array[@]}" | column --table
            else
                echo "No signals found."
            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 ""
        echo -e "PID: ${pid}"
        echo -n "Name: ${pid_name}"
        for pid_signal_name in "${!pid_signal_name_array[@]}"
        do
            local pid_signal_hex_value=$(echo "${pid_status}" | /usr/bin/awk --assign="pid_signal_name=${pid_signal_name}" '$0 ~ pid_signal_name { print $2 }')
            declare -a pid_signal_hex_value_delimited_array

            # refactor me: create function "hexToBin()"

            # 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 "{0..${#pid_signal_hex_value}}")
            do
                pid_signal_hex_value_delimited_array+=("${pid_signal_hex_value:${hex_position}:1}")
            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 "${pid_signal_hex_value_delimited_array[@]}"
            do
                if [[ "${hex_value}" =~ ^[0-9]$ ]]
                then
                    pid_signal_bin_value_4bit_array+="${bin_value_4bit_array[${hex_value}]} "
                elif [[ "${hex_value}" =~ ^[a-fA-F]$ ]]
                then
                    pid_signal_bin_value_4bit_array+="${bin_value_4bit_array[hex_value_array[${hex_value}]]} "
                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="${pid_signal_bin_value_4bit_array[@]// /}"
            unset pid_signal_bin_value_1bit_array
            for binary_position in $(eval echo "{0..$(( ${#pid_signal_bin_value_concatenated} ))}")
            do
                pid_signal_bin_value_1bit_array+=("${pid_signal_bin_value_concatenated:${binary_position}:1}")
            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 <signal_number>: <signal_name>
            local binary_array_index="${#pid_signal_bin_value_concatenated}"
            echo ""
            echo "${pid_signal_name_array[${pid_signal_name}]}"
            echo "${pid_signal_name_array[${pid_signal_name}]//${underline_regex}/-}"
            for binary_value in "${pid_signal_bin_value_1bit_array[@]}"
            do
                # signal "32" and "33" are undefined
                if [[ "${binary_array_index}" == "32" || "${binary_array_index}" == "33" ]]
                then
                    (( binary_array_index-- ))
                    continue
                elif [[ "${binary_value}" == "0" ]]
                then
                    (( binary_array_index-- ))
                    continue
                elif [[ "${binary_value}" == "1" ]]
                then
                    echo "Signal ${binary_array_index}: ${pid_signal_array[${binary_array_index}]}"
                fi

                (( binary_array_index-- ))
            done

            # output results, if there is any signal. also output results, if signal "32" and "33" are set to "1", which actually does not make any sense.
            if [[ "${pid_signal_bin_value_concatenated}" == *"1"* ]]
            then
                echo -e "Hexadecimal: ${pid_signal_hex_value_delimited_array[@]}\nBinary: ${pid_signal_bin_value_4bit_array[@]}" | column --table
            else
                echo "No signals found."
            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 ~]$ 
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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .