You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							275 lines
						
					
					
						
							6.8 KiB
						
					
					
				
			
		
		
	
	
							275 lines
						
					
					
						
							6.8 KiB
						
					
					
				| // Copyright 2018 The Prometheus Authors
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| // http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| package procfs
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // For the proc file format details,
 | |
| // see https://elixir.bootlin.com/linux/v4.17/source/net/unix/af_unix.c#L2815
 | |
| // and https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/net.h#L48.
 | |
| 
 | |
| const (
 | |
| 	netUnixKernelPtrIdx = iota
 | |
| 	netUnixRefCountIdx
 | |
| 	_
 | |
| 	netUnixFlagsIdx
 | |
| 	netUnixTypeIdx
 | |
| 	netUnixStateIdx
 | |
| 	netUnixInodeIdx
 | |
| 
 | |
| 	// Inode and Path are optional.
 | |
| 	netUnixStaticFieldsCnt = 6
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	netUnixTypeStream    = 1
 | |
| 	netUnixTypeDgram     = 2
 | |
| 	netUnixTypeSeqpacket = 5
 | |
| 
 | |
| 	netUnixFlagListen = 1 << 16
 | |
| 
 | |
| 	netUnixStateUnconnected  = 1
 | |
| 	netUnixStateConnecting   = 2
 | |
| 	netUnixStateConnected    = 3
 | |
| 	netUnixStateDisconnected = 4
 | |
| )
 | |
| 
 | |
| var errInvalidKernelPtrFmt = errors.New("Invalid Num(the kernel table slot number) format")
 | |
| 
 | |
| // NetUnixType is the type of the type field.
 | |
| type NetUnixType uint64
 | |
| 
 | |
| // NetUnixFlags is the type of the flags field.
 | |
| type NetUnixFlags uint64
 | |
| 
 | |
| // NetUnixState is the type of the state field.
 | |
| type NetUnixState uint64
 | |
| 
 | |
| // NetUnixLine represents a line of /proc/net/unix.
 | |
| type NetUnixLine struct {
 | |
| 	KernelPtr string
 | |
| 	RefCount  uint64
 | |
| 	Protocol  uint64
 | |
| 	Flags     NetUnixFlags
 | |
| 	Type      NetUnixType
 | |
| 	State     NetUnixState
 | |
| 	Inode     uint64
 | |
| 	Path      string
 | |
| }
 | |
| 
 | |
| // NetUnix holds the data read from /proc/net/unix.
 | |
| type NetUnix struct {
 | |
| 	Rows []*NetUnixLine
 | |
| }
 | |
| 
 | |
| // NewNetUnix returns data read from /proc/net/unix.
 | |
| func NewNetUnix() (*NetUnix, error) {
 | |
| 	fs, err := NewFS(DefaultMountPoint)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return fs.NewNetUnix()
 | |
| }
 | |
| 
 | |
| // NewNetUnix returns data read from /proc/net/unix.
 | |
| func (fs FS) NewNetUnix() (*NetUnix, error) {
 | |
| 	return NewNetUnixByPath(fs.proc.Path("net/unix"))
 | |
| }
 | |
| 
 | |
| // NewNetUnixByPath returns data read from /proc/net/unix by file path.
 | |
| // It might returns an error with partial parsed data, if an error occur after some data parsed.
 | |
| func NewNetUnixByPath(path string) (*NetUnix, error) {
 | |
| 	f, err := os.Open(path)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer f.Close()
 | |
| 	return NewNetUnixByReader(f)
 | |
| }
 | |
| 
 | |
| // NewNetUnixByReader returns data read from /proc/net/unix by a reader.
 | |
| // It might returns an error with partial parsed data, if an error occur after some data parsed.
 | |
| func NewNetUnixByReader(reader io.Reader) (*NetUnix, error) {
 | |
| 	nu := &NetUnix{
 | |
| 		Rows: make([]*NetUnixLine, 0, 32),
 | |
| 	}
 | |
| 	scanner := bufio.NewScanner(reader)
 | |
| 	// Omit the header line.
 | |
| 	scanner.Scan()
 | |
| 	header := scanner.Text()
 | |
| 	// From the man page of proc(5), it does not contain an Inode field,
 | |
| 	// but in actually it exists.
 | |
| 	// This code works for both cases.
 | |
| 	hasInode := strings.Contains(header, "Inode")
 | |
| 
 | |
| 	minFieldsCnt := netUnixStaticFieldsCnt
 | |
| 	if hasInode {
 | |
| 		minFieldsCnt++
 | |
| 	}
 | |
| 	for scanner.Scan() {
 | |
| 		line := scanner.Text()
 | |
| 		item, err := nu.parseLine(line, hasInode, minFieldsCnt)
 | |
| 		if err != nil {
 | |
| 			return nu, err
 | |
| 		}
 | |
| 		nu.Rows = append(nu.Rows, item)
 | |
| 	}
 | |
| 
 | |
| 	return nu, scanner.Err()
 | |
| }
 | |
| 
 | |
| func (u *NetUnix) parseLine(line string, hasInode bool, minFieldsCnt int) (*NetUnixLine, error) {
 | |
| 	fields := strings.Fields(line)
 | |
| 	fieldsLen := len(fields)
 | |
| 	if fieldsLen < minFieldsCnt {
 | |
| 		return nil, fmt.Errorf(
 | |
| 			"Parse Unix domain failed: expect at least %d fields but got %d",
 | |
| 			minFieldsCnt, fieldsLen)
 | |
| 	}
 | |
| 	kernelPtr, err := u.parseKernelPtr(fields[netUnixKernelPtrIdx])
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("Parse Unix domain num(%s) failed: %s", fields[netUnixKernelPtrIdx], err)
 | |
| 	}
 | |
| 	users, err := u.parseUsers(fields[netUnixRefCountIdx])
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("Parse Unix domain ref count(%s) failed: %s", fields[netUnixRefCountIdx], err)
 | |
| 	}
 | |
| 	flags, err := u.parseFlags(fields[netUnixFlagsIdx])
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("Parse Unix domain flags(%s) failed: %s", fields[netUnixFlagsIdx], err)
 | |
| 	}
 | |
| 	typ, err := u.parseType(fields[netUnixTypeIdx])
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("Parse Unix domain type(%s) failed: %s", fields[netUnixTypeIdx], err)
 | |
| 	}
 | |
| 	state, err := u.parseState(fields[netUnixStateIdx])
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("Parse Unix domain state(%s) failed: %s", fields[netUnixStateIdx], err)
 | |
| 	}
 | |
| 	var inode uint64
 | |
| 	if hasInode {
 | |
| 		inodeStr := fields[netUnixInodeIdx]
 | |
| 		inode, err = u.parseInode(inodeStr)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("Parse Unix domain inode(%s) failed: %s", inodeStr, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	nuLine := &NetUnixLine{
 | |
| 		KernelPtr: kernelPtr,
 | |
| 		RefCount:  users,
 | |
| 		Type:      typ,
 | |
| 		Flags:     flags,
 | |
| 		State:     state,
 | |
| 		Inode:     inode,
 | |
| 	}
 | |
| 
 | |
| 	// Path field is optional.
 | |
| 	if fieldsLen > minFieldsCnt {
 | |
| 		pathIdx := netUnixInodeIdx + 1
 | |
| 		if !hasInode {
 | |
| 			pathIdx--
 | |
| 		}
 | |
| 		nuLine.Path = fields[pathIdx]
 | |
| 	}
 | |
| 
 | |
| 	return nuLine, nil
 | |
| }
 | |
| 
 | |
| func (u NetUnix) parseKernelPtr(str string) (string, error) {
 | |
| 	if !strings.HasSuffix(str, ":") {
 | |
| 		return "", errInvalidKernelPtrFmt
 | |
| 	}
 | |
| 	return str[:len(str)-1], nil
 | |
| }
 | |
| 
 | |
| func (u NetUnix) parseUsers(hexStr string) (uint64, error) {
 | |
| 	return strconv.ParseUint(hexStr, 16, 32)
 | |
| }
 | |
| 
 | |
| func (u NetUnix) parseProtocol(hexStr string) (uint64, error) {
 | |
| 	return strconv.ParseUint(hexStr, 16, 32)
 | |
| }
 | |
| 
 | |
| func (u NetUnix) parseType(hexStr string) (NetUnixType, error) {
 | |
| 	typ, err := strconv.ParseUint(hexStr, 16, 16)
 | |
| 	if err != nil {
 | |
| 		return 0, err
 | |
| 	}
 | |
| 	return NetUnixType(typ), nil
 | |
| }
 | |
| 
 | |
| func (u NetUnix) parseFlags(hexStr string) (NetUnixFlags, error) {
 | |
| 	flags, err := strconv.ParseUint(hexStr, 16, 32)
 | |
| 	if err != nil {
 | |
| 		return 0, err
 | |
| 	}
 | |
| 	return NetUnixFlags(flags), nil
 | |
| }
 | |
| 
 | |
| func (u NetUnix) parseState(hexStr string) (NetUnixState, error) {
 | |
| 	st, err := strconv.ParseInt(hexStr, 16, 8)
 | |
| 	if err != nil {
 | |
| 		return 0, err
 | |
| 	}
 | |
| 	return NetUnixState(st), nil
 | |
| }
 | |
| 
 | |
| func (u NetUnix) parseInode(inodeStr string) (uint64, error) {
 | |
| 	return strconv.ParseUint(inodeStr, 10, 64)
 | |
| }
 | |
| 
 | |
| func (t NetUnixType) String() string {
 | |
| 	switch t {
 | |
| 	case netUnixTypeStream:
 | |
| 		return "stream"
 | |
| 	case netUnixTypeDgram:
 | |
| 		return "dgram"
 | |
| 	case netUnixTypeSeqpacket:
 | |
| 		return "seqpacket"
 | |
| 	}
 | |
| 	return "unknown"
 | |
| }
 | |
| 
 | |
| func (f NetUnixFlags) String() string {
 | |
| 	switch f {
 | |
| 	case netUnixFlagListen:
 | |
| 		return "listen"
 | |
| 	default:
 | |
| 		return "default"
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s NetUnixState) String() string {
 | |
| 	switch s {
 | |
| 	case netUnixStateUnconnected:
 | |
| 		return "unconnected"
 | |
| 	case netUnixStateConnecting:
 | |
| 		return "connecting"
 | |
| 	case netUnixStateConnected:
 | |
| 		return "connected"
 | |
| 	case netUnixStateDisconnected:
 | |
| 		return "disconnected"
 | |
| 	}
 | |
| 	return "unknown"
 | |
| }
 | |
| 
 |