1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright Authors of Cilium
16
// FilesystemType names for filesystem which are used in /proc/pid/mountinfo
17
FilesystemTypeBPFFS = "bpf"
18
FilesystemTypeCgroup2 = "cgroup2"
19
FilesystemTypeDebugFS = "debugfs"
21
mountInfoFilepath = "/proc/self/mountinfo"
24
// MountInfo is a struct representing information from /proc/pid/mountinfo. More
25
// information about file syntax:
26
// https://www.kernel.org/doc/Documentation/filesystems/proc.txt
27
type MountInfo struct {
34
OptionalFields []string
40
// parseMountInfoFile returns a slice of *MountInfo with information parsed from
42
func parseMountInfoFile(r io.Reader) ([]*MountInfo, error) {
43
var result []*MountInfo
45
scanner := bufio.NewScanner(r)
46
scanner.Split(bufio.ScanLines)
49
mountInfoRaw := scanner.Text()
51
// Optional fields (which are on the 7th position) are separated
52
// from the rest of fields by "-" character. The number of
53
// optional fields can be greater or equal to 1.
54
mountInfoSeparated := strings.Split(mountInfoRaw, " - ")
55
if len(mountInfoSeparated) != 2 {
56
return nil, fmt.Errorf("invalid mountinfo entry which has more that one '-' separator: %s", mountInfoRaw)
59
// Extract fields from both sides of mountinfo
60
mountInfoLeft := strings.Split(strings.TrimSpace(mountInfoSeparated[0]), " ")
61
mountInfoRight := strings.Split(strings.TrimSpace(mountInfoSeparated[1]), " ")
63
// Before '-' separator there should be 6 fields and unknown
64
// number of optional fields
65
if len(mountInfoLeft) < 6 {
66
return nil, fmt.Errorf("invalid mountinfo entry: %s", mountInfoRaw)
68
// After '-' separator there should be 3 fields
69
if len(mountInfoRight) != 3 {
70
return nil, fmt.Errorf("invalid mountinfo entry: %s", mountInfoRaw)
73
mountID, err := strconv.ParseInt(mountInfoLeft[0], 10, 64)
78
parentID, err := strconv.ParseInt(mountInfoLeft[1], 10, 64)
83
// Extract optional fields, which start from 7th position
84
var optionalFields []string
85
for i := 6; i < len(mountInfoLeft); i++ {
86
optionalFields = append(optionalFields, mountInfoLeft[i])
89
result = append(result, &MountInfo{
92
StDev: mountInfoLeft[2],
93
Root: mountInfoLeft[3],
94
MountPoint: mountInfoLeft[4],
95
MountOptions: mountInfoLeft[5],
96
OptionalFields: optionalFields,
97
FilesystemType: mountInfoRight[0],
98
MountSource: mountInfoRight[1],
99
SuperOptions: mountInfoRight[2],
106
// GetMountInfo returns a slice of *MountInfo with information parsed from
107
// /proc/self/mountinfo
108
func GetMountInfo() ([]*MountInfo, error) {
109
fMounts, err := os.Open(mountInfoFilepath)
111
return nil, fmt.Errorf("failed to open mount information at %s: %s", mountInfoFilepath, err)
113
defer fMounts.Close()
115
return parseMountInfoFile(fMounts)
118
func isMountFS(mountInfos []*MountInfo, mntType string, mapRoot string) (bool, bool) {
119
var mapRootMountInfo *MountInfo
121
for _, mountInfo := range mountInfos {
122
if mountInfo.MountPoint == mapRoot {
123
mapRootMountInfo = mountInfo
128
if mapRootMountInfo == nil {
132
if mapRootMountInfo.FilesystemType == mntType {
138
// IsMountFS returns two boolean values:checks whether the current mapRoot:
139
// - whether the current mapRoot has any mount
140
// - whether that mount's filesystem is of type mntType
141
func IsMountFS(infos []*MountInfo, mntType string, mapRoot string) (bool, bool) {
142
return isMountFS(infos, mntType, mapRoot)