net_unix.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. package procfs
  14. import (
  15. "bufio"
  16. "errors"
  17. "fmt"
  18. "io"
  19. "os"
  20. "strconv"
  21. "strings"
  22. )
  23. // For the proc file format details,
  24. // see https://elixir.bootlin.com/linux/v4.17/source/net/unix/af_unix.c#L2815
  25. // and https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/net.h#L48.
  26. const (
  27. netUnixKernelPtrIdx = iota
  28. netUnixRefCountIdx
  29. _
  30. netUnixFlagsIdx
  31. netUnixTypeIdx
  32. netUnixStateIdx
  33. netUnixInodeIdx
  34. // Inode and Path are optional.
  35. netUnixStaticFieldsCnt = 6
  36. )
  37. const (
  38. netUnixTypeStream = 1
  39. netUnixTypeDgram = 2
  40. netUnixTypeSeqpacket = 5
  41. netUnixFlagListen = 1 << 16
  42. netUnixStateUnconnected = 1
  43. netUnixStateConnecting = 2
  44. netUnixStateConnected = 3
  45. netUnixStateDisconnected = 4
  46. )
  47. var errInvalidKernelPtrFmt = errors.New("Invalid Num(the kernel table slot number) format")
  48. // NetUnixType is the type of the type field.
  49. type NetUnixType uint64
  50. // NetUnixFlags is the type of the flags field.
  51. type NetUnixFlags uint64
  52. // NetUnixState is the type of the state field.
  53. type NetUnixState uint64
  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. // NetUnix holds the data read from /proc/net/unix.
  66. type NetUnix struct {
  67. Rows []*NetUnixLine
  68. }
  69. // NewNetUnix returns data read from /proc/net/unix.
  70. func NewNetUnix() (*NetUnix, error) {
  71. fs, err := NewFS(DefaultMountPoint)
  72. if err != nil {
  73. return nil, err
  74. }
  75. return fs.NewNetUnix()
  76. }
  77. // NewNetUnix returns data read from /proc/net/unix.
  78. func (fs FS) NewNetUnix() (*NetUnix, error) {
  79. return NewNetUnixByPath(fs.proc.Path("net/unix"))
  80. }
  81. // NewNetUnixByPath returns data read from /proc/net/unix by file path.
  82. // It might returns an error with partial parsed data, if an error occur after some data parsed.
  83. func NewNetUnixByPath(path string) (*NetUnix, error) {
  84. f, err := os.Open(path)
  85. if err != nil {
  86. return nil, err
  87. }
  88. defer f.Close()
  89. return NewNetUnixByReader(f)
  90. }
  91. // NewNetUnixByReader returns data read from /proc/net/unix by a reader.
  92. // It might returns an error with partial parsed data, if an error occur after some data parsed.
  93. func NewNetUnixByReader(reader io.Reader) (*NetUnix, error) {
  94. nu := &NetUnix{
  95. Rows: make([]*NetUnixLine, 0, 32),
  96. }
  97. scanner := bufio.NewScanner(reader)
  98. // Omit the header line.
  99. scanner.Scan()
  100. header := scanner.Text()
  101. // From the man page of proc(5), it does not contain an Inode field,
  102. // but in actually it exists.
  103. // This code works for both cases.
  104. hasInode := strings.Contains(header, "Inode")
  105. minFieldsCnt := netUnixStaticFieldsCnt
  106. if hasInode {
  107. minFieldsCnt++
  108. }
  109. for scanner.Scan() {
  110. line := scanner.Text()
  111. item, err := nu.parseLine(line, hasInode, minFieldsCnt)
  112. if err != nil {
  113. return nu, err
  114. }
  115. nu.Rows = append(nu.Rows, item)
  116. }
  117. return nu, scanner.Err()
  118. }
  119. func (u *NetUnix) parseLine(line string, hasInode bool, minFieldsCnt int) (*NetUnixLine, error) {
  120. fields := strings.Fields(line)
  121. fieldsLen := len(fields)
  122. if fieldsLen < minFieldsCnt {
  123. return nil, fmt.Errorf(
  124. "Parse Unix domain failed: expect at least %d fields but got %d",
  125. minFieldsCnt, fieldsLen)
  126. }
  127. kernelPtr, err := u.parseKernelPtr(fields[netUnixKernelPtrIdx])
  128. if err != nil {
  129. return nil, fmt.Errorf("Parse Unix domain num(%s) failed: %s", fields[netUnixKernelPtrIdx], err)
  130. }
  131. users, err := u.parseUsers(fields[netUnixRefCountIdx])
  132. if err != nil {
  133. return nil, fmt.Errorf("Parse Unix domain ref count(%s) failed: %s", fields[netUnixRefCountIdx], err)
  134. }
  135. flags, err := u.parseFlags(fields[netUnixFlagsIdx])
  136. if err != nil {
  137. return nil, fmt.Errorf("Parse Unix domain flags(%s) failed: %s", fields[netUnixFlagsIdx], err)
  138. }
  139. typ, err := u.parseType(fields[netUnixTypeIdx])
  140. if err != nil {
  141. return nil, fmt.Errorf("Parse Unix domain type(%s) failed: %s", fields[netUnixTypeIdx], err)
  142. }
  143. state, err := u.parseState(fields[netUnixStateIdx])
  144. if err != nil {
  145. return nil, fmt.Errorf("Parse Unix domain state(%s) failed: %s", fields[netUnixStateIdx], err)
  146. }
  147. var inode uint64
  148. if hasInode {
  149. inodeStr := fields[netUnixInodeIdx]
  150. inode, err = u.parseInode(inodeStr)
  151. if err != nil {
  152. return nil, fmt.Errorf("Parse Unix domain inode(%s) failed: %s", inodeStr, err)
  153. }
  154. }
  155. nuLine := &NetUnixLine{
  156. KernelPtr: kernelPtr,
  157. RefCount: users,
  158. Type: typ,
  159. Flags: flags,
  160. State: state,
  161. Inode: inode,
  162. }
  163. // Path field is optional.
  164. if fieldsLen > minFieldsCnt {
  165. pathIdx := netUnixInodeIdx + 1
  166. if !hasInode {
  167. pathIdx--
  168. }
  169. nuLine.Path = fields[pathIdx]
  170. }
  171. return nuLine, nil
  172. }
  173. func (u NetUnix) parseKernelPtr(str string) (string, error) {
  174. if !strings.HasSuffix(str, ":") {
  175. return "", errInvalidKernelPtrFmt
  176. }
  177. return str[:len(str)-1], nil
  178. }
  179. func (u NetUnix) parseUsers(hexStr string) (uint64, error) {
  180. return strconv.ParseUint(hexStr, 16, 32)
  181. }
  182. func (u NetUnix) parseProtocol(hexStr string) (uint64, error) {
  183. return strconv.ParseUint(hexStr, 16, 32)
  184. }
  185. func (u NetUnix) parseType(hexStr string) (NetUnixType, error) {
  186. typ, err := strconv.ParseUint(hexStr, 16, 16)
  187. if err != nil {
  188. return 0, err
  189. }
  190. return NetUnixType(typ), nil
  191. }
  192. func (u NetUnix) parseFlags(hexStr string) (NetUnixFlags, error) {
  193. flags, err := strconv.ParseUint(hexStr, 16, 32)
  194. if err != nil {
  195. return 0, err
  196. }
  197. return NetUnixFlags(flags), nil
  198. }
  199. func (u NetUnix) parseState(hexStr string) (NetUnixState, error) {
  200. st, err := strconv.ParseInt(hexStr, 16, 8)
  201. if err != nil {
  202. return 0, err
  203. }
  204. return NetUnixState(st), nil
  205. }
  206. func (u NetUnix) parseInode(inodeStr string) (uint64, error) {
  207. return strconv.ParseUint(inodeStr, 10, 64)
  208. }
  209. func (t NetUnixType) String() string {
  210. switch t {
  211. case netUnixTypeStream:
  212. return "stream"
  213. case netUnixTypeDgram:
  214. return "dgram"
  215. case netUnixTypeSeqpacket:
  216. return "seqpacket"
  217. }
  218. return "unknown"
  219. }
  220. func (f NetUnixFlags) String() string {
  221. switch f {
  222. case netUnixFlagListen:
  223. return "listen"
  224. default:
  225. return "default"
  226. }
  227. }
  228. func (s NetUnixState) String() string {
  229. switch s {
  230. case netUnixStateUnconnected:
  231. return "unconnected"
  232. case netUnixStateConnecting:
  233. return "connecting"
  234. case netUnixStateConnected:
  235. return "connected"
  236. case netUnixStateDisconnected:
  237. return "disconnected"
  238. }
  239. return "unknown"
  240. }