github.com/cilium/cilium@v1.16.2/pkg/mountinfo/mountinfo.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package mountinfo
     5  
     6  import (
     7  	"bufio"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  const (
    16  	mountInfoFilepath = "/proc/self/mountinfo"
    17  )
    18  
    19  // MountInfo is a struct representing information from /proc/pid/mountinfo. More
    20  // information about file syntax:
    21  // https://www.kernel.org/doc/Documentation/filesystems/proc.txt
    22  type MountInfo struct {
    23  	MountID        int64
    24  	ParentID       int64
    25  	StDev          string
    26  	Root           string
    27  	MountPoint     string
    28  	MountOptions   string
    29  	OptionalFields []string
    30  	FilesystemType string
    31  	MountSource    string
    32  	SuperOptions   string
    33  }
    34  
    35  // parseMountInfoFile returns a slice of *MountInfo with information parsed from
    36  // the given reader
    37  func parseMountInfoFile(r io.Reader) ([]*MountInfo, error) {
    38  	var result []*MountInfo
    39  
    40  	scanner := bufio.NewScanner(r)
    41  	scanner.Split(bufio.ScanLines)
    42  
    43  	for scanner.Scan() {
    44  		mountInfoRaw := scanner.Text()
    45  
    46  		// Optional fields (which are on the 7th position) are separated
    47  		// from the rest of fields by "-" character. The number of
    48  		// optional fields can be greater or equal to 1.
    49  		mountInfoSeparated := strings.Split(mountInfoRaw, " - ")
    50  		if len(mountInfoSeparated) != 2 {
    51  			return nil, fmt.Errorf("invalid mountinfo entry which has more that one '-' separator: %s", mountInfoRaw)
    52  		}
    53  
    54  		// Extract fields from both sides of mountinfo
    55  		mountInfoLeft := strings.Split(mountInfoSeparated[0], " ")
    56  		mountInfoRight := strings.Split(mountInfoSeparated[1], " ")
    57  
    58  		// Before '-' separator there should be 6 fields and unknown
    59  		// number of optional fields
    60  		if len(mountInfoLeft) < 6 {
    61  			return nil, fmt.Errorf("invalid mountinfo entry: %s", mountInfoRaw)
    62  		}
    63  		// After '-' separator there should be 3 fields
    64  		if len(mountInfoRight) != 3 {
    65  			return nil, fmt.Errorf("invalid mountinfo entry: %s", mountInfoRaw)
    66  		}
    67  
    68  		mountID, err := strconv.ParseInt(mountInfoLeft[0], 10, 64)
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  
    73  		parentID, err := strconv.ParseInt(mountInfoLeft[1], 10, 64)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  
    78  		// Extract optional fields, which start from 7th position
    79  		var optionalFields []string
    80  		for i := 6; i < len(mountInfoLeft); i++ {
    81  			optionalFields = append(optionalFields, mountInfoLeft[i])
    82  		}
    83  
    84  		result = append(result, &MountInfo{
    85  			MountID:        mountID,
    86  			ParentID:       parentID,
    87  			StDev:          mountInfoLeft[2],
    88  			Root:           mountInfoLeft[3],
    89  			MountPoint:     mountInfoLeft[4],
    90  			MountOptions:   mountInfoLeft[5],
    91  			OptionalFields: optionalFields,
    92  			FilesystemType: mountInfoRight[0],
    93  			MountSource:    mountInfoRight[1],
    94  			SuperOptions:   mountInfoRight[2],
    95  		})
    96  	}
    97  
    98  	if err := scanner.Err(); err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	return result, nil
   103  }
   104  
   105  // GetMountInfo returns a slice of *MountInfo with information parsed from
   106  // /proc/self/mountinfo
   107  func GetMountInfo() ([]*MountInfo, error) {
   108  	fMounts, err := os.Open(mountInfoFilepath)
   109  	if err != nil {
   110  		return nil, fmt.Errorf("failed to open mount information at %s: %w", mountInfoFilepath, err)
   111  	}
   112  	defer fMounts.Close()
   113  
   114  	return parseMountInfoFile(fMounts)
   115  }