forked from Velocidex/velociraptor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.go
148 lines (120 loc) · 3.85 KB
/
utils.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
Velociraptor - Hunting Evil
Copyright (C) 2019 Velocidex Innovations.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package main
import (
"context"
"fmt"
"io"
"os"
"os/signal"
"strings"
"syscall"
humanize "github.com/dustin/go-humanize"
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
logging "www.velocidex.com/golang/velociraptor/logging"
vfilter "www.velocidex.com/golang/vfilter"
)
func InstallSignalHandler(scope *vfilter.Scope) context.Context {
// Wait for signal. When signal is received we shut down the
// server.
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
ctx, cancel := context.WithCancel(context.Background())
go func() {
// Wait for the signal on this channel.
<-quit
scope.Log("Shutting down due to interrupt.")
scope.Close()
// Only cancel the context once the scope is fully
// destroyed. This ensures all the destructors have
// enougb time to finish when we exit the program
cancel()
}()
return ctx
}
// Turns os.Stdout into into file_store.WriteSeekCloser
type StdoutWrapper struct {
io.Writer
}
func (self *StdoutWrapper) Seek(offset int64, whence int) (int64, error) {
return 0, nil
}
func (self *StdoutWrapper) Close() error {
return nil
}
func (self *StdoutWrapper) Truncate(offset int64) error {
return nil
}
// https://golangcode.com/download-a-file-with-progress/
// WriteCounter counts the number of bytes written to it. It implements to the io.Writer
// interface and we can pass this into io.TeeReader() which will report progress on each
// write cycle.
type WriteCounter struct {
name string
Total uint64
}
func (wc *WriteCounter) Write(p []byte) (int, error) {
n := len(p)
wc.Total += uint64(n)
wc.PrintProgress()
return n, nil
}
func (wc WriteCounter) PrintProgress() {
// Clear the line by using a character return to go back to the start and remove
// the remaining characters by filling it with spaces
fmt.Printf("\r%s", strings.Repeat(" ", 35))
// Return again and print current status of download
// We use the humanize package to print the bytes in a meaningful way (e.g. 10 MB)
fmt.Printf("\rDownloading %s ... %s complete", wc.name, humanize.Bytes(wc.Total))
}
var (
// Set to true when the client gracefully exits.
exiting = false
)
// This is only called when there is something very wrong! If the
// executor loop somehow exits due to panic or a bug we will not be
// able to communicate with the endpoint. We have to hard exit here to
// ensure the process can be restarted. This is a last resort!
func on_error(config_obj *config_proto.Config) {
// It's ok we are supposed to exit.
if exiting {
return
}
logger := logging.GetLogger(config_obj, &logging.ClientComponent)
logger.Error("Exiting hard due to bug or KillKillKill! This should not happen!")
os.Exit(-1)
}
func install_sig_handler() (context.Context, context.CancelFunc) {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
ctx, cancel := context.WithCancel(context.Background())
go func() {
select {
case <-quit:
// Ordered shutdown now.
exiting = true
cancel()
case <-ctx.Done():
return
}
}()
return ctx, cancel
}