-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheckProcs.go
More file actions
259 lines (219 loc) · 5.6 KB
/
checkProcs.go
File metadata and controls
259 lines (219 loc) · 5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"strconv"
"strings"
)
// Exit codes for monitoring Sensu/Nagios
const (
// OK will return 0
OK = 0
// WARNING will return 1
WARNING = 1
// CRITICAL will return 2
CRITICAL = 2
// UNKNOWN will return 3
UNKNOWN = 3
)
// Process is the generic interface that is implemented on every platform
// and provides common operations for processes.
type Process interface {
// Pid is the process ID for this process.
Pid() int
// PPid is the parent process ID for this process.
PPid() int
// Executable name running this process. This is not a path to the
// executable.
Executable() string
}
// Processes returns all processes.
//
// This of course will be a point-in-time snapshot of when this method was
// called. Some operating systems don't provide snapshot capability of the
// process table, in which case the process table returned might contain
// ephemeral entities that happened to be running when this was called.
//
// Example:
// procs, _ := Processes()
//
func Processes() ([]Process, error) {
return processes()
}
// FindProcess looks up a single process by pid.
//
// Process will be nil and error will be nil if a matching process is
// not found.
//
// Example:
// foo, _ := FindProcess(4256)
// fmt.Println(foo.Executable(), foo.Pid())
// for _, i := range procs {
// if i.Executable()
func FindProcess(pid int) (Process, error) {
return findProcess(pid)
}
// UnixProcess is an implementation of Process that contains Unix-specific
// fields and information.
type UnixProcess struct {
pid int
ppid int
state rune
pgrp int
sid int
binary string
}
// Pid simply return pid of the specific process
func (p *UnixProcess) Pid() int {
return p.pid
}
// PPid simply return ppid of the specific process
func (p *UnixProcess) PPid() int {
return p.ppid
}
// Executable simply return name of the process
func (p *UnixProcess) Executable() string {
return p.binary
}
// findProcess is returning all information about the specific process
func findProcess(pid int) (Process, error) {
dir := fmt.Sprintf("/proc/%d", pid)
_, err := os.Stat(dir)
if err != nil {
// file does not exist
if os.IsNotExist(err) {
return nil, nil
}
// other error, if any
return nil, err
}
return newUnixProcess(pid)
}
// newUnixProcess is adding pid to the Process type
// and call Refresh function to fill missing data
func newUnixProcess(pid int) (*UnixProcess, error) {
p := &UnixProcess{pid: pid}
return p, p.Refresh()
}
// Refresh reloads all the data associated with this process.
func (p *UnixProcess) Refresh() error {
statPath := fmt.Sprintf("/proc/%d/stat", p.pid)
dataBytes, err := ioutil.ReadFile(statPath)
if err != nil {
return err
}
// First, parse out the image name
data := string(dataBytes)
binStart := strings.IndexRune(data, '(') + 1
binEnd := strings.IndexRune(data[binStart:], ')')
// setup name of the proces on to the pointer
p.binary = data[binStart : binStart+binEnd]
// Move past the image name and start parsing the rest
data = data[binStart+binEnd+2:]
// setup rest of the process types in the pointer
// and return error if any
_, err = fmt.Sscanf(data,
"%c %d %d %d",
&p.state,
&p.ppid,
&p.pgrp,
&p.sid)
return err
}
// processes return all unix processes as a struct of Process type
func processes() ([]Process, error) {
d, err := os.Open("/proc")
if err != nil {
return nil, err
}
defer d.Close()
results := make([]Process, 0, 50)
for {
// Readdir(10) return slice of first 10 processes
// if in for{} going for the next 10 processes till return al of them
fis, err := d.Readdir(10)
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
// now we need to iterate over the slice of first 10 processes
// we can call their names by .Name() as it's interface FileInfo
// we need to use for as we don't know how many processes there is
// at the /proc diretory, so it's better to get 10 parse and get another 10
for _, fi := range fis {
// We only care about directories, since all pids are dirs
if !fi.IsDir() {
continue
}
// We only care if the name starts with a numeric
name := fi.Name()
if name[0] < '0' || name[0] > '9' {
continue
}
// From this point forward, any errors we just ignore, because
// it might simply be that the process doesn't exist anymore.
// convert string to int
pid, err := strconv.ParseInt(name, 10, 0)
if err != nil {
continue
}
p, err := newUnixProcess(int(pid))
if err != nil {
continue
}
results = append(results, p)
}
}
return results, nil
}
// Main function to actually start programm
func main() {
run, command, err := Command()
if err != nil {
fmt.Printf("Error: %v", err)
os.Exit(UNKNOWN)
}
for _, i := range run {
if i.Executable() == command && i.PPid() == 1 {
fmt.Printf("Process exist: %v, pid: %d", i.Executable(), i.Pid())
os.Exit(OK)
}
}
fmt.Printf("Process do not exist: %v", command)
os.Exit(CRITICAL)
}
// Command function is checking if we run it with the correct
// parameters and return process information
func Command() ([]Process, string, error) {
if len(os.Args) != 3 {
help()
}
if os.Args[1] != "-c" {
help()
}
command := os.Args[2]
if command == "" {
help()
}
procs, err := Processes()
if err != nil {
return nil, "", err
}
return procs, command, nil
}
// help function to show help how to execute
// this script
func help() {
fmt.Println("")
fmt.Println(" -c string")
fmt.Println(" process name (string)")
fmt.Println("")
fmt.Println(" example:")
fmt.Println(" ./check_proc -c \"sshd\"")
fmt.Println("")
os.Exit(UNKNOWN)
}