1717package collector
1818
1919import (
20- "bufio "
20+ "bytes "
2121 "errors"
2222 "fmt"
23- "io"
2423 "log/slog"
2524 "os"
2625 "slices"
@@ -31,6 +30,8 @@ import (
3130
3231 "github.com/alecthomas/kingpin/v2"
3332 "golang.org/x/sys/unix"
33+
34+ "github.com/prometheus/procfs"
3435)
3536
3637const (
@@ -179,60 +180,51 @@ func stuckMountWatcher(mountPoint string, success chan struct{}, logger *slog.Lo
179180}
180181
181182func mountPointDetails (logger * slog.Logger ) ([]filesystemLabels , error ) {
182- file , err := os .Open (procFilePath ("1/mountinfo" ))
183+ fs , err := procfs .NewFS (* procPath )
184+ if err != nil {
185+ return nil , fmt .Errorf ("failed to open procfs: %w" , err )
186+ }
187+ mountInfo , err := fs .GetProcMounts (1 )
183188 if errors .Is (err , os .ErrNotExist ) {
184189 // Fallback to `/proc/self/mountinfo` if `/proc/1/mountinfo` is missing due hidepid.
185190 logger .Debug ("Reading root mounts failed, falling back to self mounts" , "err" , err )
186- file , err = os . Open ( procFilePath ( "self/mountinfo" ) )
191+ mountInfo , err = fs . GetMounts ( )
187192 }
188193 if err != nil {
189194 return nil , err
190195 }
191- defer file .Close ()
192196
193- return parseFilesystemLabels (file )
197+ return parseFilesystemLabels (mountInfo )
194198}
195199
196- func parseFilesystemLabels (r io. Reader ) ([]filesystemLabels , error ) {
200+ func parseFilesystemLabels (mountInfo [] * procfs. MountInfo ) ([]filesystemLabels , error ) {
197201 var filesystems []filesystemLabels
198202
199- scanner := bufio .NewScanner (r )
200- for scanner .Scan () {
201- parts := strings .Fields (scanner .Text ())
202-
203- if len (parts ) < 11 {
204- return nil , fmt .Errorf ("malformed mount point information: %q" , scanner .Text ())
205- }
206-
203+ for _ , mount := range mountInfo {
207204 major , minor := 0 , 0
208- _ , err := fmt .Sscanf (parts [ 2 ] , "%d:%d" , & major , & minor )
205+ _ , err := fmt .Sscanf (mount . MajorMinorVer , "%d:%d" , & major , & minor )
209206 if err != nil {
210- return nil , fmt .Errorf ("malformed mount point information: %q" , scanner .Text ())
211- }
212-
213- m := 5
214- for parts [m + 1 ] != "-" {
215- m ++
207+ return nil , fmt .Errorf ("malformed mount point MajorMinorVer: %q" , mount .MajorMinorVer )
216208 }
217209
218210 // Ensure we handle the translation of \040 and \011
219211 // as per fstab(5).
220- parts [ 4 ] = strings .ReplaceAll (parts [ 4 ] , "\\ 040" , " " )
221- parts [ 4 ] = strings .ReplaceAll (parts [ 4 ] , "\\ 011" , "\t " )
212+ mount . MountPoint = strings .ReplaceAll (mount . MountPoint , "\\ 040" , " " )
213+ mount . MountPoint = strings .ReplaceAll (mount . MountPoint , "\\ 011" , "\t " )
222214
223215 filesystems = append (filesystems , filesystemLabels {
224- device : parts [ m + 3 ] ,
225- mountPoint : rootfsStripPrefix (parts [ 4 ] ),
226- fsType : parts [ m + 2 ] ,
227- mountOptions : parts [ 5 ] ,
228- superOptions : parts [ 10 ] ,
216+ device : mount . Source ,
217+ mountPoint : rootfsStripPrefix (mount . MountPoint ),
218+ fsType : mount . FSType ,
219+ mountOptions : mountOptionsString ( mount . Options ) ,
220+ superOptions : mountOptionsString ( mount . SuperOptions ) ,
229221 major : strconv .Itoa (major ),
230222 minor : strconv .Itoa (minor ),
231223 deviceError : "" ,
232224 })
233225 }
234226
235- return filesystems , scanner . Err ()
227+ return filesystems , nil
236228}
237229
238230// see https://github.com/prometheus/node_exporter/issues/3157#issuecomment-2422761187
@@ -244,3 +236,15 @@ func isFilesystemReadOnly(labels filesystemLabels) bool {
244236
245237 return false
246238}
239+
240+ func mountOptionsString (m map [string ]string ) string {
241+ b := new (bytes.Buffer )
242+ for key , value := range m {
243+ if value == "" {
244+ fmt .Fprintf (b , "%s" , key )
245+ } else {
246+ fmt .Fprintf (b , "%s=%s" , key , value )
247+ }
248+ }
249+ return b .String ()
250+ }
0 commit comments