forked from jpillora/overseer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
proc_slave_windows.go
130 lines (116 loc) · 3.04 KB
/
proc_slave_windows.go
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
//go:build windows
// +build windows
package overseer
import (
"context"
"fmt"
"os"
"strings"
"time"
"github.com/yusufpapurcu/wmi"
)
var (
Timeout = 3 * time.Second
)
type Win32_Process struct {
Name string
ExecutablePath *string
CommandLine *string
Priority uint32
CreationDate *time.Time
ProcessID uint32
ThreadCount uint32
Status *string
ReadOperationCount uint64
ReadTransferCount uint64
WriteOperationCount uint64
WriteTransferCount uint64
CSCreationClassName string
CSName string
Caption *string
CreationClassName string
Description *string
ExecutionState *uint16
HandleCount uint32
KernelModeTime uint64
MaximumWorkingSetSize *uint32
MinimumWorkingSetSize *uint32
OSCreationClassName string
OSName string
OtherOperationCount uint64
OtherTransferCount uint64
PageFaults uint32
PageFileUsage uint32
ParentProcessID uint32
PeakPageFileUsage uint32
PeakVirtualSize uint64
PeakWorkingSetSize uint32
PrivatePageCount uint64
TerminationDate *time.Time
UserModeTime uint64
WorkingSetSize uint64
}
func (sp *slave) watchParent() error {
sp.masterPid = os.Getppid()
proc, err := os.FindProcess(sp.masterPid)
if err != nil {
return fmt.Errorf("master process: %s", err)
}
sp.masterProc = proc
go func() {
//send signal 0 to master process forever
for {
//should not error as long as the process is alive
if _, err := GetWin32Proc(int32(sp.masterPid)); err != nil {
os.Exit(1)
}
time.Sleep(2 * time.Second)
}
}()
return nil
}
func GetWin32Proc(pid int32) ([]Win32_Process, error) {
return GetWin32ProcWithContext(context.Background(), pid)
}
func GetWin32ProcWithContext(ctx context.Context, pid int32) ([]Win32_Process, error) {
var dst []Win32_Process
query := fmt.Sprintf("WHERE ProcessId = %d", pid)
q := wmi.CreateQuery(&dst, query)
err := WMIQueryWithContext(ctx, q, &dst)
if err != nil {
return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
}
if len(dst) == 0 {
return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty")
}
return dst, nil
}
func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
if _, ok := ctx.Deadline(); !ok {
ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
defer cancel()
ctx = ctxTimeout
}
errChan := make(chan error, 1)
go func() {
errChan <- wmi.Query(query, dst, connectServerArgs...)
}()
select {
case <-ctx.Done():
return ctx.Err()
case err := <-errChan:
return err
}
}
// overwrite: see https://github.com/georgiosB/overseer/issues/56#issuecomment-656405955
func overwrite(dst, src string) error {
old := strings.TrimSuffix(dst, ".exe") + "-old.exe"
if err := move(old, dst); err != nil {
return err
}
if err := move(dst, src); err != nil {
return err
}
os.Remove(old)
return nil
}