1
2
3
4
5
6
7
8
9
10
11
12
13
14 package procfs
15
16 import (
17 "bufio"
18 "fmt"
19 "io"
20 "os"
21 "strconv"
22 "strings"
23 )
24
25
26
27
28
29
30
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
46 type NetUNIXType uint64
47
48
49 type NetUNIXFlags uint64
50
51
52 type NetUNIXState uint64
53
54
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
67 type NetUNIX struct {
68 Rows []*NetUNIXLine
69 }
70
71
72 func (fs FS) NetUNIX() (*NetUNIX, error) {
73 return readNetUNIX(fs.proc.Path("net/unix"))
74 }
75
76
77 func readNetUNIX(file string) (*NetUNIX, error) {
78
79
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
90 func parseNetUNIX(r io.Reader) (*NetUNIX, error) {
91
92 s := bufio.NewScanner(r)
93 s.Scan()
94
95
96
97 hasInode := strings.Contains(s.Text(), "Inode")
98
99
100
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("%s: /proc/net/unix encountered data %q: %w", ErrFileParse, 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("%s: /proc/net/unix encountered data: %w", ErrFileParse, 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("%w: expected at least %d fields but got %d", ErrFileParse, min, l)
130 }
131
132
133
134
135 kernelPtr := strings.TrimSuffix(fields[0], ":")
136
137 users, err := u.parseUsers(fields[1])
138 if err != nil {
139 return nil, fmt.Errorf("%s: ref count %q: %w", ErrFileParse, fields[1], err)
140 }
141
142 flags, err := u.parseFlags(fields[3])
143 if err != nil {
144 return nil, fmt.Errorf("%s: Unable to parse flags %q: %w", ErrFileParse, fields[3], err)
145 }
146
147 typ, err := u.parseType(fields[4])
148 if err != nil {
149 return nil, fmt.Errorf("%s: Failed to parse type %q: %w", ErrFileParse, fields[4], err)
150 }
151
152 state, err := u.parseState(fields[5])
153 if err != nil {
154 return nil, fmt.Errorf("%s: Failed to parse state %q: %w", ErrFileParse, 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("%s failed to parse inode %q: %w", ErrFileParse, 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
175 if l > min {
176
177
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
View as plain text