cubefs

Форк
0
180 строк · 5.2 Кб
1
// Copyright 2019 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
	"bytes"
19
	"fmt"
20
	"strconv"
21
	"strings"
22

23
	"github.com/prometheus/procfs/internal/util"
24
)
25

26
// A MountInfo is a type that describes the details, options
27
// for each mount, parsed from /proc/self/mountinfo.
28
// The fields described in each entry of /proc/self/mountinfo
29
// is described in the following man page.
30
// http://man7.org/linux/man-pages/man5/proc.5.html
31
type MountInfo struct {
32
	// Unique ID for the mount
33
	MountID int
34
	// The ID of the parent mount
35
	ParentID int
36
	// The value of `st_dev` for the files on this FS
37
	MajorMinorVer string
38
	// The pathname of the directory in the FS that forms
39
	// the root for this mount
40
	Root string
41
	// The pathname of the mount point relative to the root
42
	MountPoint string
43
	// Mount options
44
	Options map[string]string
45
	// Zero or more optional fields
46
	OptionalFields map[string]string
47
	// The Filesystem type
48
	FSType string
49
	// FS specific information or "none"
50
	Source string
51
	// Superblock options
52
	SuperOptions map[string]string
53
}
54

55
// Reads each line of the mountinfo file, and returns a list of formatted MountInfo structs.
56
func parseMountInfo(info []byte) ([]*MountInfo, error) {
57
	mounts := []*MountInfo{}
58
	scanner := bufio.NewScanner(bytes.NewReader(info))
59
	for scanner.Scan() {
60
		mountString := scanner.Text()
61
		parsedMounts, err := parseMountInfoString(mountString)
62
		if err != nil {
63
			return nil, err
64
		}
65
		mounts = append(mounts, parsedMounts)
66
	}
67

68
	err := scanner.Err()
69
	return mounts, err
70
}
71

72
// Parses a mountinfo file line, and converts it to a MountInfo struct.
73
// An important check here is to see if the hyphen separator, as if it does not exist,
74
// it means that the line is malformed.
75
func parseMountInfoString(mountString string) (*MountInfo, error) {
76
	var err error
77

78
	mountInfo := strings.Split(mountString, " ")
79
	mountInfoLength := len(mountInfo)
80
	if mountInfoLength < 10 {
81
		return nil, fmt.Errorf("couldn't find enough fields in mount string: %s", mountString)
82
	}
83

84
	if mountInfo[mountInfoLength-4] != "-" {
85
		return nil, fmt.Errorf("couldn't find separator in expected field: %s", mountInfo[mountInfoLength-4])
86
	}
87

88
	mount := &MountInfo{
89
		MajorMinorVer:  mountInfo[2],
90
		Root:           mountInfo[3],
91
		MountPoint:     mountInfo[4],
92
		Options:        mountOptionsParser(mountInfo[5]),
93
		OptionalFields: nil,
94
		FSType:         mountInfo[mountInfoLength-3],
95
		Source:         mountInfo[mountInfoLength-2],
96
		SuperOptions:   mountOptionsParser(mountInfo[mountInfoLength-1]),
97
	}
98

99
	mount.MountID, err = strconv.Atoi(mountInfo[0])
100
	if err != nil {
101
		return nil, fmt.Errorf("failed to parse mount ID")
102
	}
103
	mount.ParentID, err = strconv.Atoi(mountInfo[1])
104
	if err != nil {
105
		return nil, fmt.Errorf("failed to parse parent ID")
106
	}
107
	// Has optional fields, which is a space separated list of values.
108
	// Example: shared:2 master:7
109
	if mountInfo[6] != "" {
110
		mount.OptionalFields, err = mountOptionsParseOptionalFields(mountInfo[6 : mountInfoLength-4])
111
		if err != nil {
112
			return nil, err
113
		}
114
	}
115
	return mount, nil
116
}
117

118
// mountOptionsIsValidField checks a string against a valid list of optional fields keys.
119
func mountOptionsIsValidField(s string) bool {
120
	switch s {
121
	case
122
		"shared",
123
		"master",
124
		"propagate_from",
125
		"unbindable":
126
		return true
127
	}
128
	return false
129
}
130

131
// mountOptionsParseOptionalFields parses a list of optional fields strings into a double map of strings.
132
func mountOptionsParseOptionalFields(o []string) (map[string]string, error) {
133
	optionalFields := make(map[string]string)
134
	for _, field := range o {
135
		optionSplit := strings.SplitN(field, ":", 2)
136
		value := ""
137
		if len(optionSplit) == 2 {
138
			value = optionSplit[1]
139
		}
140
		if mountOptionsIsValidField(optionSplit[0]) {
141
			optionalFields[optionSplit[0]] = value
142
		}
143
	}
144
	return optionalFields, nil
145
}
146

147
// mountOptionsParser parses the mount options, superblock options.
148
func mountOptionsParser(mountOptions string) map[string]string {
149
	opts := make(map[string]string)
150
	options := strings.Split(mountOptions, ",")
151
	for _, opt := range options {
152
		splitOption := strings.Split(opt, "=")
153
		if len(splitOption) < 2 {
154
			key := splitOption[0]
155
			opts[key] = ""
156
		} else {
157
			key, value := splitOption[0], splitOption[1]
158
			opts[key] = value
159
		}
160
	}
161
	return opts
162
}
163

164
// GetMounts retrieves mountinfo information from `/proc/self/mountinfo`.
165
func GetMounts() ([]*MountInfo, error) {
166
	data, err := util.ReadFileNoStat("/proc/self/mountinfo")
167
	if err != nil {
168
		return nil, err
169
	}
170
	return parseMountInfo(data)
171
}
172

173
// GetProcMounts retrieves mountinfo information from a processes' `/proc/<pid>/mountinfo`.
174
func GetProcMounts(pid int) ([]*MountInfo, error) {
175
	data, err := util.ReadFileNoStat(fmt.Sprintf("/proc/%d/mountinfo", pid))
176
	if err != nil {
177
		return nil, err
178
	}
179
	return parseMountInfo(data)
180
}
181

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.