diff --git a/mountinfo.go b/mountinfo.go index 92e77076..9414a12f 100644 --- a/mountinfo.go +++ b/mountinfo.go @@ -177,3 +177,21 @@ func GetProcMounts(pid int) ([]*MountInfo, error) { } return parseMountInfo(data) } + +// GetMounts retrieves mountinfo information from `/proc/self/mountinfo`. +func (fs FS) GetMounts() ([]*MountInfo, error) { + data, err := util.ReadFileNoStat(fs.proc.Path("self/mountinfo")) + if err != nil { + return nil, err + } + return parseMountInfo(data) +} + +// GetProcMounts retrieves mountinfo information from a processes' `/proc//mountinfo`. +func (fs FS) GetProcMounts(pid int) ([]*MountInfo, error) { + data, err := util.ReadFileNoStat(fs.proc.Path(fmt.Sprintf("%d/mountinfo", pid))) + if err != nil { + return nil, err + } + return parseMountInfo(data) +} diff --git a/mountinfo_test.go b/mountinfo_test.go index 5cabc500..97451285 100644 --- a/mountinfo_test.go +++ b/mountinfo_test.go @@ -15,6 +15,8 @@ package procfs import ( "reflect" "testing" + + "github.com/google/go-cmp/cmp" ) func TestMountInfo(t *testing.T) { @@ -182,3 +184,188 @@ func TestMountInfo(t *testing.T) { } } } + +func TestFSMountInfo(t *testing.T) { + fs, err := NewFS(procTestFixtures) + if err != nil { + t.Fatalf("failed to open procfs: %v", err) + } + + want := []*MountInfo{ + { + MountID: 1, + ParentID: 1, + MajorMinorVer: "0:5", + Root: "/", + Options: map[string]string{"/root": ""}, + OptionalFields: map[string]string{"shared": "8"}, + FSType: "rootfs", + Source: "rootfs", + SuperOptions: map[string]string{"rw": ""}, + }, + { + MountID: 16, + ParentID: 21, + MajorMinorVer: "0:16", + Root: "/", + MountPoint: "/sys", + Options: map[string]string{"nodev": "", "noexec": "", "nosuid": "", "relatime": "", "rw": ""}, + OptionalFields: map[string]string{"shared": "7"}, + FSType: "sysfs", + Source: "sysfs", + SuperOptions: map[string]string{"rw": ""}, + }, + { + MountID: 17, + ParentID: 21, + MajorMinorVer: "0:4", + Root: "/", + MountPoint: "/proc", + Options: map[string]string{"nodev": "", "noexec": "", "nosuid": "", "relatime": "", "rw": ""}, + OptionalFields: map[string]string{"shared": "12"}, + FSType: "proc", + Source: "proc", + SuperOptions: map[string]string{"rw": ""}, + }, + { + MountID: 21, + MajorMinorVer: "8:1", + Root: "/", + MountPoint: "/", + Options: map[string]string{"relatime": "", "rw": ""}, + OptionalFields: map[string]string{"shared": "1"}, + FSType: "ext4", + Source: "/dev/sda1", + SuperOptions: map[string]string{"data": "ordered", "errors": "remount-ro", "rw": ""}, + }, + { + MountID: 194, + ParentID: 21, + MajorMinorVer: "0:42", + Root: "/", + MountPoint: "/mnt/nfs/test", + Options: map[string]string{"rw": ""}, + OptionalFields: map[string]string{"shared": "144"}, + FSType: "nfs4", + Source: "192.168.1.1:/srv/test", + SuperOptions: map[string]string{ + "acdirmax": "60", + "acdirmin": "30", + "acregmax": "60", + "acregmin": "3", + "addr": "192.168.1.1", + "clientaddr": "192.168.1.5", + "hard": "", + "local_lock": "none", + "namlen": "255", + "port": "0", + "proto": "tcp", + "retrans": "2", + "rsize": "1048576", + "rw": "", + "sec": "sys", + "timeo": "600", + "vers": "4.0", + "wsize": "1048576", + }, + }, + { + MountID: 177, + ParentID: 21, + MajorMinorVer: "0:42", + Root: "/", + MountPoint: "/mnt/nfs/test", + Options: map[string]string{"rw": ""}, + OptionalFields: map[string]string{"shared": "130"}, + FSType: "nfs4", + Source: "192.168.1.1:/srv/test", + SuperOptions: map[string]string{ + "acdirmax": "60", + "acdirmin": "30", + "acregmax": "60", + "acregmin": "3", + "addr": "192.168.1.1", + "clientaddr": "192.168.1.5", + "hard": "", + "local_lock": "none", + "namlen": "255", + "port": "0", + "proto": "tcp", + "retrans": "2", + "rsize": "1048576", + "rw": "", + "sec": "sys", + "timeo": "600", + "vers": "4.0", + "wsize": "1048576", + }, + }, + { + MountID: 1398, + ParentID: 798, + MajorMinorVer: "0:44", + Root: "/", + MountPoint: "/mnt/nfs/test", + Options: map[string]string{"relatime": "", "rw": ""}, + OptionalFields: map[string]string{"shared": "1154"}, + FSType: "nfs", + Source: "192.168.1.1:/srv/test", + SuperOptions: map[string]string{ + "addr": "192.168.1.1", + "hard": "", + "local_lock": "none", + "mountaddr": "192.168.1.1", + "mountport": "49602", + "mountproto": "udp", + "mountvers": "3", + "namlen": "255", + "proto": "udp", + "retrans": "3", + "rsize": "32768", + "rw": "", + "sec": "sys", + "timeo": "11", + "vers": "3", + "wsize": "32768", + }, + }, + { + MountID: 1128, + ParentID: 67, + MajorMinorVer: "253:0", + Root: "/var/lib/containers/storage/overlay", + MountPoint: "/var/lib/containers/storage/overlay", + Options: map[string]string{"relatime": "", "rw": ""}, + OptionalFields: map[string]string{}, + FSType: "xfs", + Source: "/dev/mapper/rhel-root", + SuperOptions: map[string]string{ + "attr2": "", + "inode64": "", + "logbsize": "32k", + "logbufs": "8", + "noquota": "", + "rw": "", + "seclabel": "", + }, + }, + } + + got, err := fs.GetMounts() + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Fatalf("unexpected mountpoints (-want +got):\n%s", diff) + } + + got, err = fs.GetProcMounts(26231) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Fatalf("unexpected mountpoints (-want +got):\n%s", diff) + } +} diff --git a/testdata/fixtures.ttar b/testdata/fixtures.ttar index cc5b39e9..2de7ad30 100644 --- a/testdata/fixtures.ttar +++ b/testdata/fixtures.ttar @@ -174,6 +174,18 @@ Max realtime priority 0 0 Max realtime timeout unlimited unlimited us Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/26231/mountinfo +Lines: 8 +1 1 0:5 / /root rw,nosuid shared:8 - rootfs rootfs rw +16 21 0:16 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw +17 21 0:4 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw +21 0 8:1 / / rw,relatime shared:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=ordered +194 21 0:42 / /mnt/nfs/test rw shared:144 - nfs4 192.168.1.1:/srv/test rw,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.5,addr=192.168.1.1,local_lock=none +177 21 0:42 / /mnt/nfs/test rw shared:130 - nfs4 192.168.1.1:/srv/test rw,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.5,addr=192.168.1.1,local_lock=none +1398 798 0:44 / /mnt/nfs/test rw,relatime shared:1154 - nfs 192.168.1.1:/srv/test rw,vers=3,rsize=32768,wsize=32768,namlen=255,hard,proto=udp,timeo=11,retrans=3,sec=sys,mountaddr=192.168.1.1,mountvers=3,mountport=49602,mountproto=udp,local_lock=none,addr=192.168.1.1 +1128 67 253:0 /var/lib/containers/storage/overlay /var/lib/containers/storage/overlay rw,relatime - xfs /dev/mapper/rhel-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/proc/26231/mountstats Lines: 20 device rootfs mounted on / with fstype rootfs