...

Source file src/github.com/prometheus/procfs/net_unix.go

Documentation: github.com/prometheus/procfs

     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("%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  	// 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("%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  	// 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  

View as plain text