1
2
3
4
19
20 package mount
21
22 import (
23 "fmt"
24 "os"
25 "strconv"
26 "strings"
27 "syscall"
28
29 utilio "k8s.io/utils/io"
30 )
31
32 const (
33
34 expectedAtLeastNumFieldsPerMountInfo = 10
35
36 maxListTries = 3
37 )
38
39
40 func IsCorruptedMnt(err error) bool {
41 if err == nil {
42 return false
43 }
44 var underlyingError error
45 switch pe := err.(type) {
46 case nil:
47 return false
48 case *os.PathError:
49 underlyingError = pe.Err
50 case *os.LinkError:
51 underlyingError = pe.Err
52 case *os.SyscallError:
53 underlyingError = pe.Err
54 }
55
56 return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE || underlyingError == syscall.EIO || underlyingError == syscall.EACCES
57 }
58
59
60 type MountInfo struct {
61
62 ID int
63
64 ParentID int
65
66
67 Major int
68
69
70 Minor int
71
72 Root string
73
74 Source string
75
76 MountPoint string
77
78 OptionalFields []string
79
80 FsType string
81
82 MountOptions []string
83
84 SuperOptions []string
85 }
86
87
88 func ParseMountInfo(filename string) ([]MountInfo, error) {
89 content, err := utilio.ConsistentRead(filename, maxListTries)
90 if err != nil {
91 return []MountInfo{}, err
92 }
93 contentStr := string(content)
94 infos := []MountInfo{}
95
96 for _, line := range strings.Split(contentStr, "\n") {
97 if line == "" {
98
99 continue
100 }
101
102 fields := strings.Fields(line)
103 if len(fields) < expectedAtLeastNumFieldsPerMountInfo {
104 return nil, fmt.Errorf("wrong number of fields in (expected at least %d, got %d): %s", expectedAtLeastNumFieldsPerMountInfo, len(fields), line)
105 }
106 id, err := strconv.Atoi(fields[0])
107 if err != nil {
108 return nil, err
109 }
110 parentID, err := strconv.Atoi(fields[1])
111 if err != nil {
112 return nil, err
113 }
114 mm := strings.Split(fields[2], ":")
115 if len(mm) != 2 {
116 return nil, fmt.Errorf("parsing '%s' failed: unexpected minor:major pair %s", line, mm)
117 }
118 major, err := strconv.Atoi(mm[0])
119 if err != nil {
120 return nil, fmt.Errorf("parsing '%s' failed: unable to parse major device id, err:%v", mm[0], err)
121 }
122 minor, err := strconv.Atoi(mm[1])
123 if err != nil {
124 return nil, fmt.Errorf("parsing '%s' failed: unable to parse minor device id, err:%v", mm[1], err)
125 }
126
127 info := MountInfo{
128 ID: id,
129 ParentID: parentID,
130 Major: major,
131 Minor: minor,
132 Root: fields[3],
133 MountPoint: fields[4],
134 MountOptions: strings.Split(fields[5], ","),
135 }
136
137 i := 6
138 for ; i < len(fields) && fields[i] != "-"; i++ {
139 info.OptionalFields = append(info.OptionalFields, fields[i])
140 }
141
142 i++
143 if len(fields)-i < 3 {
144 return nil, fmt.Errorf("expect 3 fields in %s, got %d", line, len(fields)-i)
145 }
146 info.FsType = fields[i]
147 info.Source = fields[i+1]
148 info.SuperOptions = strings.Split(fields[i+2], ",")
149 infos = append(infos, info)
150 }
151 return infos, nil
152 }
153
154
155
156 func isMountPointMatch(mp MountPoint, dir string) bool {
157 deletedDir := fmt.Sprintf("%s\\040(deleted)", dir)
158 return ((mp.Path == dir) || (mp.Path == deletedDir))
159 }
160
View as plain text