3
3
package metrics
4
4
5
5
import (
6
+ "encoding/json"
6
7
"errors"
7
8
"os"
8
9
"os/exec"
9
- "strconv"
10
10
"strings"
11
11
"time"
12
12
)
13
13
14
+ // SmbStatusServerID represents a server_id output field
15
+ type SmbStatusServerID struct {
16
+ PID string `json:"pid"`
17
+ TaskID string `json:"task_id"`
18
+ VNN string `json:"vnn"`
19
+ UniqueID string `json:"unique_id"`
20
+ }
21
+
22
+ // SmbStatusEncryption represents a encryption output field
23
+ type SmbStatusEncryption struct {
24
+ Cipher string `json:"cipher"`
25
+ Degree string `json:"degree"`
26
+ }
27
+
28
+ // SmbStatusSigning represents a signing output field
29
+ type SmbStatusSigning struct {
30
+ Cipher string `json:"cipher"`
31
+ Degree string `json:"degree"`
32
+ }
33
+
14
34
// SmbStatusShare represents a single entry from the output of 'smbstatus -S'
15
35
type SmbStatusShare struct {
16
- Service string
17
- PID int64
18
- Machine string
19
- ConnectedAt string
20
- ConnectedTime time.Time
21
- Encryption string
22
- Signing string
36
+ Service string `json:"service"`
37
+ ServerID SmbStatusServerID `json:"server_id"`
38
+ Machine string `json:"machine"`
39
+ ConnectedAt string `json:"connected_at"`
40
+ Encryption SmbStatusEncryption `json:"encryption"`
41
+ Signing SmbStatusSigning `json:"signing"`
42
+ }
43
+
44
+ // SmbStatusSession represents a session output field
45
+ type SmbStatusSession struct {
46
+ SessionID string `json:"session_id"`
47
+ ServerID SmbStatusServerID `json:"server_id"`
48
+ UID int `json:"uid"`
49
+ GID int `json:"gid"`
50
+ Username string `json:"username"`
51
+ Groupname string `json:"groupname"`
52
+ RemoteMachine string `json:"remote_machine"`
53
+ Hostname string `json:"hostname"`
54
+ SessionDialect string `json:"session_dialect"`
55
+ Encryption SmbStatusEncryption `json:"encryption"`
56
+ Signing SmbStatusSigning `json:"signing"`
57
+ }
58
+
59
+ // SmbStatusFileID represents a fileid output field
60
+ type SmbStatusFileID struct {
61
+ DevID int64 `json:"devid"`
62
+ Inode int64 `json:"inode"`
63
+ Extid int32 `json:"extid"`
64
+ }
65
+
66
+ // SmbStatusLockedFile represents a locked-file output field
67
+ type SmbStatusLockedFile struct {
68
+ ServicePath string `json:"service_path"`
69
+ Filename string `json:"filename"`
70
+ FileID SmbStatusFileID `json:"fileid"`
71
+ NumPendingDeletes int `json:"num_pending_deletes"`
72
+ }
73
+
74
+ // SmbStatusJSON represents output of 'smbstatus --json'
75
+ type SmbStatusJSON struct {
76
+ Timestamp string `json:"timestamp"`
77
+ Version string `json:"version"`
78
+ SmbConf string `json:"smb_conf"`
79
+ Sessions map [string ]SmbStatusSession `json:"sessions"`
80
+ TCons map [string ]SmbStatusShare `json:"tcons"`
81
+ LockedFiles map [string ]SmbStatusLockedFile `json:"locked_files"`
23
82
}
24
83
25
84
// SmbStatusProc represents a single entry from the output of 'smbstatus -p'
26
85
type SmbStatusProc struct {
27
- PID int64
86
+ PID string
28
87
Username string
29
88
Group string
30
89
Machine string
@@ -35,8 +94,8 @@ type SmbStatusProc struct {
35
94
36
95
// SmbStatusLock represents a single entry from the output of 'smbstatus -L'
37
96
type SmbStatusLock struct {
38
- PID int64
39
- UserID int64
97
+ PID string
98
+ UserID string
40
99
DenyMode string
41
100
Access string
42
101
RW string
@@ -78,11 +137,29 @@ func RunSmbStatusVersion() (string, error) {
78
137
79
138
// RunSmbStatusShares executes 'smbstatus -S' on host container
80
139
func RunSmbStatusShares () ([]SmbStatusShare , error ) {
81
- dat , err := executeSmbStatusCommand ("-S" )
140
+ // Case 1: using new json output
141
+ dat , err := executeSmbStatusCommand ("-S --json" )
142
+ if err == nil {
143
+ return parseSmbStatusSharesAsJSON (dat )
144
+ }
145
+ // Case 2: fallback to raw-text output
146
+ dat , err = executeSmbStatusCommand ("-S" )
147
+ if err == nil {
148
+ return parseSmbStatusShares (dat )
149
+ }
150
+ return []SmbStatusShare {}, err
151
+ }
152
+
153
+ func parseSmbStatusSharesAsJSON (dat string ) ([]SmbStatusShare , error ) {
154
+ shares := []SmbStatusShare {}
155
+ res , err := parseSmbStatusJSON (dat )
82
156
if err != nil {
83
- return []SmbStatusShare {}, err
157
+ return shares , err
158
+ }
159
+ for _ , share := range res .TCons {
160
+ shares = append (shares , share )
84
161
}
85
- return parseSmbStatusShares ( dat )
162
+ return shares , nil
86
163
}
87
164
88
165
// RunSmbStatusLocks executes 'smbstatus -L' on host container
@@ -106,15 +183,19 @@ func RunSmbStatusProcs() ([]SmbStatusProc, error) {
106
183
// SmbStatusSharesByMachine converts the output of RunSmbStatusShares into map
107
184
// indexed by machine's host
108
185
func SmbStatusSharesByMachine () (map [string ][]SmbStatusShare , error ) {
109
- ret := map [string ][]SmbStatusShare {}
110
186
shares , err := RunSmbStatusShares ()
111
187
if err != nil {
112
- return ret , err
188
+ return map [ string ][] SmbStatusShare {} , err
113
189
}
190
+ return makeSmbSharesMap (shares ), nil
191
+ }
192
+
193
+ func makeSmbSharesMap (shares []SmbStatusShare ) map [string ][]SmbStatusShare {
194
+ ret := map [string ][]SmbStatusShare {}
114
195
for _ , share := range shares {
115
196
ret [share .Machine ] = append (ret [share .Machine ], share )
116
197
}
117
- return ret , nil
198
+ return ret
118
199
}
119
200
120
201
func executeSmbStatusCommand (args ... string ) (string , error ) {
@@ -175,18 +256,11 @@ func parseSmbStatusShares(data string) ([]SmbStatusShare, error) {
175
256
// Parse data into internal repr
176
257
share := SmbStatusShare {}
177
258
share .Service = parseSubstr (ln , serviceIndex )
178
- pid , err := parseInt64 (ln , pidIndex )
179
- if err != nil {
180
- return shares , err
181
- }
182
- share .PID = pid
259
+ share .ServerID .PID = parseSubstr (ln , pidIndex )
183
260
share .Machine = parseSubstr (ln , machineIndex )
184
261
share .ConnectedAt = parseSubstr2 (ln , connectedAtIndex , encryptionIndex )
185
- share .Encryption = parseSubstr (ln , encryptionIndex )
186
- share .Signing = parseSubstr (ln , signingIndex )
187
- if t , err := parseTime (share .ConnectedAt ); err == nil {
188
- share .ConnectedTime = t
189
- }
262
+ share .Encryption .Cipher = parseSubstr (ln , encryptionIndex )
263
+ share .Signing .Cipher = parseSubstr (ln , signingIndex )
190
264
191
265
// Ignore "IPC$"
192
266
if share .Service == "IPC$" {
@@ -239,11 +313,7 @@ func parseSmbStatusProcs(data string) ([]SmbStatusProc, error) {
239
313
}
240
314
// Parse data into internal repr
241
315
proc := SmbStatusProc {}
242
- pid , err := parseInt64 (ln , pidIndex )
243
- if err != nil {
244
- return procs , err
245
- }
246
- proc .PID = pid
316
+ proc .PID = parseSubstr (ln , pidIndex )
247
317
proc .Username = parseSubstr (ln , usernameIndex )
248
318
proc .Group = parseSubstr (ln , groupIndex )
249
319
proc .Machine = parseSubstr (ln , machineIndex )
@@ -300,16 +370,8 @@ func parseSmbStatusLocks(data string) ([]SmbStatusLock, error) {
300
370
}
301
371
// Parse data into internal repr
302
372
lock := SmbStatusLock {}
303
- pid , err := parseInt64 (ln , pidIndex )
304
- if err != nil {
305
- return locks , err
306
- }
307
- lock .PID = pid
308
- user , err := parseInt64 (ln , userIndex )
309
- if err != nil {
310
- return locks , err
311
- }
312
- lock .UserID = user
373
+ lock .PID = parseSubstr (ln , pidIndex )
374
+ lock .UserID = parseSubstr (ln , userIndex )
313
375
lock .DenyMode = parseSubstr (ln , denyModeIndex )
314
376
lock .Access = parseSubstr (ln , accessIndex )
315
377
lock .RW = parseSubstr (ln , rwIndex )
@@ -320,10 +382,6 @@ func parseSmbStatusLocks(data string) ([]SmbStatusLock, error) {
320
382
return locks , nil
321
383
}
322
384
323
- func parseInt64 (s string , startIndex int ) (int64 , error ) {
324
- return strconv .ParseInt (parseSubstr (s , startIndex ), 10 , 64 )
325
- }
326
-
327
385
func parseSubstr (s string , startIndex int ) string {
328
386
sub := strings .TrimSpace (s [startIndex :])
329
387
fields := strings .Fields (sub )
@@ -337,7 +395,7 @@ func parseSubstr2(s string, startIndex, endIndex int) string {
337
395
return strings .TrimSpace (s [startIndex :endIndex ])
338
396
}
339
397
340
- func parseTime (s string ) (time.Time , error ) {
398
+ func ParseTime (s string ) (time.Time , error ) {
341
399
layouts := []string {
342
400
time .ANSIC ,
343
401
time .UnixDate ,
@@ -351,3 +409,11 @@ func parseTime(s string) (time.Time, error) {
351
409
// samba's lib/util/time.c uses non standad layout...
352
410
return time.Time {}, errors .New ("unknow time format " + s )
353
411
}
412
+
413
+ // parseSmbStatusJSON parses to output of 'smbstatus --json' into internal
414
+ // representation.
415
+ func parseSmbStatusJSON (data string ) (* SmbStatusJSON , error ) {
416
+ res := SmbStatusJSON {}
417
+ err := json .Unmarshal ([]byte (data ), & res )
418
+ return & res , err
419
+ }
0 commit comments