cubefs

Форк
0
257 строк · 5.9 Кб
1
// Copyright 2018 The Prometheus Authors
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software
9
// distributed under the License is distributed on an "AS IS" BASIS,
10
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
// See the License for the specific language governing permissions and
12
// limitations under the License.
13

14
package procfs
15

16
import (
17
	"bufio"
18
	"fmt"
19
	"io"
20
	"os"
21
	"strconv"
22
	"strings"
23
)
24

25
// For the proc file format details,
26
// see https://elixir.bootlin.com/linux/v4.17/source/net/unix/af_unix.c#L2815
27
// and https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/net.h#L48.
28

29
// Constants for the various /proc/net/unix enumerations.
30
// TODO: match against x/sys/unix or similar?
31
const (
32
	netUnixTypeStream    = 1
33
	netUnixTypeDgram     = 2
34
	netUnixTypeSeqpacket = 5
35

36
	netUnixFlagDefault = 0
37
	netUnixFlagListen  = 1 << 16
38

39
	netUnixStateUnconnected  = 1
40
	netUnixStateConnecting   = 2
41
	netUnixStateConnected    = 3
42
	netUnixStateDisconnected = 4
43
)
44

45
// NetUNIXType is the type of the type field.
46
type NetUNIXType uint64
47

48
// NetUNIXFlags is the type of the flags field.
49
type NetUNIXFlags uint64
50

51
// NetUNIXState is the type of the state field.
52
type NetUNIXState uint64
53

54
// NetUNIXLine represents a line of /proc/net/unix.
55
type NetUNIXLine struct {
56
	KernelPtr string
57
	RefCount  uint64
58
	Protocol  uint64
59
	Flags     NetUNIXFlags
60
	Type      NetUNIXType
61
	State     NetUNIXState
62
	Inode     uint64
63
	Path      string
64
}
65

66
// NetUNIX holds the data read from /proc/net/unix.
67
type NetUNIX struct {
68
	Rows []*NetUNIXLine
69
}
70

71
// NetUNIX returns data read from /proc/net/unix.
72
func (fs FS) NetUNIX() (*NetUNIX, error) {
73
	return readNetUNIX(fs.proc.Path("net/unix"))
74
}
75

76
// readNetUNIX reads data in /proc/net/unix format from the specified file.
77
func readNetUNIX(file string) (*NetUNIX, error) {
78
	// This file could be quite large and a streaming read is desirable versus
79
	// reading the entire contents at once.
80
	f, err := os.Open(file)
81
	if err != nil {
82
		return nil, err
83
	}
84
	defer f.Close()
85

86
	return parseNetUNIX(f)
87
}
88

89
// parseNetUNIX creates a NetUnix structure from the incoming stream.
90
func parseNetUNIX(r io.Reader) (*NetUNIX, error) {
91
	// Begin scanning by checking for the existence of Inode.
92
	s := bufio.NewScanner(r)
93
	s.Scan()
94

95
	// From the man page of proc(5), it does not contain an Inode field,
96
	// but in actually it exists. This code works for both cases.
97
	hasInode := strings.Contains(s.Text(), "Inode")
98

99
	// Expect a minimum number of fields, but Inode and Path are optional:
100
	// Num       RefCount Protocol Flags    Type St Inode Path
101
	minFields := 6
102
	if hasInode {
103
		minFields++
104
	}
105

106
	var nu NetUNIX
107
	for s.Scan() {
108
		line := s.Text()
109
		item, err := nu.parseLine(line, hasInode, minFields)
110
		if err != nil {
111
			return nil, fmt.Errorf("failed to parse /proc/net/unix data %q: %w", line, err)
112
		}
113

114
		nu.Rows = append(nu.Rows, item)
115
	}
116

117
	if err := s.Err(); err != nil {
118
		return nil, fmt.Errorf("failed to scan /proc/net/unix data: %w", err)
119
	}
120

121
	return &nu, nil
122
}
123

124
func (u *NetUNIX) parseLine(line string, hasInode bool, min int) (*NetUNIXLine, error) {
125
	fields := strings.Fields(line)
126

127
	l := len(fields)
128
	if l < min {
129
		return nil, fmt.Errorf("expected at least %d fields but got %d", min, l)
130
	}
131

132
	// Field offsets are as follows:
133
	// Num       RefCount Protocol Flags    Type St Inode Path
134

135
	kernelPtr := strings.TrimSuffix(fields[0], ":")
136

137
	users, err := u.parseUsers(fields[1])
138
	if err != nil {
139
		return nil, fmt.Errorf("failed to parse ref count %q: %w", fields[1], err)
140
	}
141

142
	flags, err := u.parseFlags(fields[3])
143
	if err != nil {
144
		return nil, fmt.Errorf("failed to parse flags %q: %w", fields[3], err)
145
	}
146

147
	typ, err := u.parseType(fields[4])
148
	if err != nil {
149
		return nil, fmt.Errorf("failed to parse type %q: %w", fields[4], err)
150
	}
151

152
	state, err := u.parseState(fields[5])
153
	if err != nil {
154
		return nil, fmt.Errorf("failed to parse state %q: %w", fields[5], err)
155
	}
156

157
	var inode uint64
158
	if hasInode {
159
		inode, err = u.parseInode(fields[6])
160
		if err != nil {
161
			return nil, fmt.Errorf("failed to parse inode %q: %w", fields[6], err)
162
		}
163
	}
164

165
	n := &NetUNIXLine{
166
		KernelPtr: kernelPtr,
167
		RefCount:  users,
168
		Type:      typ,
169
		Flags:     flags,
170
		State:     state,
171
		Inode:     inode,
172
	}
173

174
	// Path field is optional.
175
	if l > min {
176
		// Path occurs at either index 6 or 7 depending on whether inode is
177
		// already present.
178
		pathIdx := 7
179
		if !hasInode {
180
			pathIdx--
181
		}
182

183
		n.Path = fields[pathIdx]
184
	}
185

186
	return n, nil
187
}
188

189
func (u NetUNIX) parseUsers(s string) (uint64, error) {
190
	return strconv.ParseUint(s, 16, 32)
191
}
192

193
func (u NetUNIX) parseType(s string) (NetUNIXType, error) {
194
	typ, err := strconv.ParseUint(s, 16, 16)
195
	if err != nil {
196
		return 0, err
197
	}
198

199
	return NetUNIXType(typ), nil
200
}
201

202
func (u NetUNIX) parseFlags(s string) (NetUNIXFlags, error) {
203
	flags, err := strconv.ParseUint(s, 16, 32)
204
	if err != nil {
205
		return 0, err
206
	}
207

208
	return NetUNIXFlags(flags), nil
209
}
210

211
func (u NetUNIX) parseState(s string) (NetUNIXState, error) {
212
	st, err := strconv.ParseInt(s, 16, 8)
213
	if err != nil {
214
		return 0, err
215
	}
216

217
	return NetUNIXState(st), nil
218
}
219

220
func (u NetUNIX) parseInode(s string) (uint64, error) {
221
	return strconv.ParseUint(s, 10, 64)
222
}
223

224
func (t NetUNIXType) String() string {
225
	switch t {
226
	case netUnixTypeStream:
227
		return "stream"
228
	case netUnixTypeDgram:
229
		return "dgram"
230
	case netUnixTypeSeqpacket:
231
		return "seqpacket"
232
	}
233
	return "unknown"
234
}
235

236
func (f NetUNIXFlags) String() string {
237
	switch f {
238
	case netUnixFlagListen:
239
		return "listen"
240
	default:
241
		return "default"
242
	}
243
}
244

245
func (s NetUNIXState) String() string {
246
	switch s {
247
	case netUnixStateUnconnected:
248
		return "unconnected"
249
	case netUnixStateConnecting:
250
		return "connecting"
251
	case netUnixStateConnected:
252
		return "connected"
253
	case netUnixStateDisconnected:
254
		return "disconnected"
255
	}
256
	return "unknown"
257
}
258

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.