├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum └── sigmask.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | sigmask 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Pranay Kanwar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sigmask 2 | ======= 3 | 4 | Decode and print process signal masks, given a process id on Linux. 5 | Decodes signal masks (SigCgt, SigIgn, SigBlk, ShdPnd, SigPnd) in `/proc/PID/status` 6 | 7 | To install/build and run. 8 | 9 | ``` 10 | $ go install -v github.com/r4um/sigmask 11 | $ ${GOPATH:=~/go}/bin/sigmask 12 | ``` 13 | 14 | Usage 15 | ``` 16 | $ sigmask 17 | missing process id or path to status file 18 | Usage: sigmask [flags] pid 19 | Usage: sigmask [flags] proc_status_path 20 | Usage: sigmask [-noname] -mask=MASK 21 | -blocked 22 | Show blocked 23 | -caught 24 | Show caught 25 | -ignored 26 | Show ignored 27 | -mask string 28 | Decode mask 29 | -noname 30 | Do not print signal name 31 | -pending 32 | Show pending 33 | -shpending 34 | Show shared pending 35 | ``` 36 | 37 | Examples 38 | ``` 39 | $ sigmask $$ 40 | SigPnd 41 | ShdPnd 42 | SigBlk SIGCHLD 43 | SigIgn SIGQUIT,SIGTSTP,SIGTTIN,SIGTTOU 44 | SigCgt SIGHUP,SIGINT,SIGILL,SIGTRAP,SIGABRT,SIGBUS,SIGFPE,SIGUSR1,SIGSEGV,SIGUSR2,SIGPIPE,SIGALRM,SIGTERM,SIGCHLD,SIGXCPU,SIGXFSZ,SIGVTALRM,SIGWINCH,SIGSYS 45 | $ sigmask 1 46 | SigPnd 47 | ShdPnd 48 | SigBlk SIGHUP,SIGINT,SIGUSR1,SIGUSR2,SIGTERM,SIGCHLD,SIGWINCH,SIGPWR,SIGRTMIN,SIGRTMIN+1,SIGRTMIN+2,SIGRTMIN+3,SIGRTMIN+4,SIGRTMIN+5,SIGRTMIN+6,SIGRTMIN+7,SIGRTMIN+13,SIGRTMIN+14,SIGRTMIN+15,SIGRTMAX-14,SIGRTMAX-13,SIGRTMAX-12,SIGRTMAX-10,SIGRTMAX-9,SIGRTMAX-8,SIGRTMAX-7,SIGRTMAX-6,SIGRTMAX-5,SIGRTMAX-4,SIGRTMAX-3,SIGRTMAX-2,SIGRTMAX-1 49 | SigIgn SIGPIPE 50 | SigCgt SIGQUIT,SIGILL,SIGABRT,SIGBUS,SIGFPE,SIGSEGV 51 | $ sigmask /proc/25/status 52 | SigPnd 53 | ShdPnd 54 | SigBlk 55 | SigIgn SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,SIGABRT,SIGBUS,SIGFPE,SIGKILL,SIGUSR1,SIGSEGV,SIGUSR2,SIGPIPE,SIGALRM,SIGTERM,SIGSTKFLT,SIGCHLD,SIGCONT,SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU,SIGURG,SIGXCPU,SIGXFSZ,SIGVTALRM,SIGPROF,SIGWINCH,SIGIO,SIGPWR,SIGSYS,SIGRTMIN-2,SIGRTMIN-1,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 56 | SigCgt 57 | ``` 58 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/r4um/sigmask 2 | 3 | go 1.24.2 4 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4um/sigmask/cb1500e837d9eb2a90f50554e00994fa4851fc6d/go.sum -------------------------------------------------------------------------------- /sigmask.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/csv" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "math/big" 9 | "os" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // SIGNAMES Generated from 15 | // kill -l | tr "\t" "\n" | ruby -ne '$_.scan(/(\d+)\) (.*)/) {|f,k| puts "#{f}:\"#{k}\"," }' 16 | var SIGNAMES = map[int]string{ 17 | 1: "SIGHUP", 18 | 2: "SIGINT", 19 | 3: "SIGQUIT", 20 | 4: "SIGILL", 21 | 5: "SIGTRAP", 22 | 6: "SIGABRT", 23 | 7: "SIGBUS", 24 | 8: "SIGFPE", 25 | 9: "SIGKILL", 26 | 10: "SIGUSR1", 27 | 11: "SIGSEGV", 28 | 12: "SIGUSR2", 29 | 13: "SIGPIPE", 30 | 14: "SIGALRM", 31 | 15: "SIGTERM", 32 | 16: "SIGSTKFLT", 33 | 17: "SIGCHLD", 34 | 18: "SIGCONT", 35 | 19: "SIGSTOP", 36 | 20: "SIGTSTP", 37 | 21: "SIGTTIN", 38 | 22: "SIGTTOU", 39 | 23: "SIGURG", 40 | 24: "SIGXCPU", 41 | 25: "SIGXFSZ", 42 | 26: "SIGVTALRM", 43 | 27: "SIGPROF", 44 | 28: "SIGWINCH", 45 | 29: "SIGIO", 46 | 30: "SIGPWR", 47 | 31: "SIGSYS", 48 | 32: "SIGRTMIN-2", 49 | 33: "SIGRTMIN-1", 50 | 34: "SIGRTMIN", 51 | 35: "SIGRTMIN+1", 52 | 36: "SIGRTMIN+2", 53 | 37: "SIGRTMIN+3", 54 | 38: "SIGRTMIN+4", 55 | 39: "SIGRTMIN+5", 56 | 40: "SIGRTMIN+6", 57 | 41: "SIGRTMIN+7", 58 | 42: "SIGRTMIN+8", 59 | 43: "SIGRTMIN+9", 60 | 44: "SIGRTMIN+10", 61 | 45: "SIGRTMIN+11", 62 | 46: "SIGRTMIN+12", 63 | 47: "SIGRTMIN+13", 64 | 48: "SIGRTMIN+14", 65 | 49: "SIGRTMIN+15", 66 | 50: "SIGRTMAX-14", 67 | 51: "SIGRTMAX-13", 68 | 52: "SIGRTMAX-12", 69 | 53: "SIGRTMAX-11", 70 | 54: "SIGRTMAX-10", 71 | 55: "SIGRTMAX-9", 72 | 56: "SIGRTMAX-8", 73 | 57: "SIGRTMAX-7", 74 | 58: "SIGRTMAX-6", 75 | 59: "SIGRTMAX-5", 76 | 60: "SIGRTMAX-4", 77 | 61: "SIGRTMAX-3", 78 | 62: "SIGRTMAX-2", 79 | 63: "SIGRTMAX-1", 80 | 64: "SIGRTMAX", 81 | } 82 | 83 | func ParseStatuses(r io.Reader) map[string]string { 84 | reader := csv.NewReader(r) 85 | reader.Comma = ':' 86 | reader.FieldsPerRecord = -1 87 | 88 | statusMap := make(map[string]string) 89 | 90 | for { 91 | record, err := reader.Read() 92 | if err == io.EOF { 93 | break 94 | } 95 | if err != nil { 96 | fmt.Fprintf(os.Stderr, "error: %s\n", err) 97 | return nil 98 | } 99 | statusMap[record[0]] = strings.TrimSpace(record[1]) 100 | } 101 | 102 | return statusMap 103 | } 104 | 105 | // DecodeSigmask decodes signal mask. See function render_sigset_t in kernel 106 | // source fs/proc/array.c 107 | func DecodeSigmask(mask string, nosigname bool) string { 108 | var n big.Int 109 | 110 | _, ok := n.SetString(mask, 16) 111 | if !ok { 112 | fmt.Fprintf(os.Stderr, "unable to parse hex mask entry %s\n", mask) 113 | os.Exit(2) 114 | } 115 | 116 | var signals []string 117 | 118 | for i := 0; i < n.BitLen(); i++ { 119 | if n.Bit(i) == 1 { 120 | name, ok := SIGNAMES[i+1] 121 | if nosigname || !ok { 122 | name = strconv.Itoa(i + 1) 123 | } 124 | signals = append(signals, name) 125 | } 126 | } 127 | return strings.Join(signals, ",") 128 | } 129 | 130 | func Usage() { 131 | fmt.Fprintf(os.Stderr, "Usage: %s [flags] pid\n", os.Args[0]) 132 | fmt.Fprintf(os.Stderr, "Usage: %s [flags] proc_status_path\n", os.Args[0]) 133 | fmt.Fprintf(os.Stderr, "Usage: %s [-noname] -mask=MASK\n", os.Args[0]) 134 | flag.PrintDefaults() 135 | } 136 | 137 | func main() { 138 | sigmasks := []struct { 139 | name string 140 | selected *bool 141 | }{ 142 | {"SigPnd", flag.Bool("pending", false, "Show pending")}, 143 | {"ShdPnd", flag.Bool("shpending", false, "Show shared pending")}, 144 | {"SigBlk", flag.Bool("blocked", false, "Show blocked")}, 145 | {"SigIgn", flag.Bool("ignored", false, "Show ignored")}, 146 | {"SigCgt", flag.Bool("caught", false, "Show caught")}, 147 | } 148 | 149 | var mask string 150 | flag.StringVar(&mask, "mask", "", "Decode mask") 151 | 152 | var nosigname bool 153 | flag.BoolVar(&nosigname, "noname", false, "Do not print signal name") 154 | 155 | flag.Usage = Usage 156 | flag.Parse() 157 | 158 | if mask != "" { 159 | fmt.Println(DecodeSigmask(mask, nosigname)) 160 | os.Exit(0) 161 | } 162 | 163 | args := flag.Args() 164 | 165 | if len(args) < 1 { 166 | fmt.Fprintf(os.Stderr, "missing process id or path to status file\n") 167 | flag.Usage() 168 | os.Exit(1) 169 | } 170 | if len(args) > 1 { 171 | fmt.Fprintf(os.Stderr, "unexpected arguments: %v", args[1:]) 172 | flag.Usage() 173 | os.Exit(1) 174 | } 175 | 176 | path := args[0] 177 | 178 | file, err := os.Open(path) 179 | var err2 error 180 | if err != nil { 181 | file, err2 = os.Open(fmt.Sprintf("/proc/%s/status", path)) 182 | if err2 != nil { 183 | fmt.Fprintf(os.Stderr, "error: %s\nerror: %s\n", err, err2) 184 | os.Exit(1) 185 | } else { 186 | defer file.Close() 187 | } 188 | } else { 189 | defer file.Close() 190 | } 191 | 192 | statusMap := ParseStatuses(file) 193 | 194 | printAll := true 195 | for _, mask := range sigmasks { 196 | if *mask.selected { 197 | printAll = false 198 | break 199 | } 200 | } 201 | for _, mask := range sigmasks { 202 | if printAll || *mask.selected { 203 | value := DecodeSigmask(statusMap[mask.name], nosigname) 204 | fmt.Printf("%s %s %s\n", mask.name, statusMap[mask.name], value) 205 | } 206 | } 207 | } 208 | --------------------------------------------------------------------------------