From 11714fb6a36d0662e7f9d8ab53e4479d6b9daacc Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 27 Sep 2017 15:36:46 +0100 Subject: [PATCH] Use stat_t.st_rdev to compare block devices I implemented /dev/disk/by-uuid on my platform but using absolute links (where udev typically uses relative) which broke the code in `os.DeviceUUID`. Rather than just patch that up directly instead stat both the target and candidate devices and pick one with matching major:minor in st_rdev. This saves manually building paths to resolve symlinks and I think should be more robust overall. I also removed the initial stat of /dev/disk/by-uuid, I believe `ioutil.Readdir` will correctly return an error if the path does not exist. Signed-off-by: Ian Campbell --- pkg/os/os.go | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/pkg/os/os.go b/pkg/os/os.go index 57945d57f..a9086b7d4 100644 --- a/pkg/os/os.go +++ b/pkg/os/os.go @@ -22,6 +22,7 @@ import ( "io/ioutil" "os" "path/filepath" + "syscall" containerdmount "github.com/containerd/containerd/mount" "github.com/containerd/fifo" @@ -130,28 +131,41 @@ func (RealOS) LookupMount(path string) (containerdmount.Info, error) { return containerdmount.Lookup(path) } +// blkdev returns the rdev of a block device or an error if not a block device +func blkrdev(device string) (uint64, error) { + info, err := os.Stat(device) + if err != nil { + return 0, err + } + stat := info.Sys().(*syscall.Stat_t) + if (stat.Mode & syscall.S_IFMT) != syscall.S_IFBLK { + return 0, fmt.Errorf("%s is not a block device", device) + } + return stat.Rdev, nil +} + // DeviceUUID gets device uuid of a device. The passed in device should be // an absolute path of the device. func (RealOS) DeviceUUID(device string) (string, error) { - const uuidDir = "/dev/disk/by-uuid" - if _, err := os.Stat(uuidDir); err != nil { + rdev, err := blkrdev(device) + if err != nil { return "", err } + + const uuidDir = "/dev/disk/by-uuid" files, err := ioutil.ReadDir(uuidDir) if err != nil { return "", err } for _, file := range files { path := filepath.Join(uuidDir, file.Name()) - target, err := os.Readlink(path) + + trdev, err := blkrdev(path) if err != nil { - return "", err + continue } - dev, err := filepath.Abs(filepath.Join(uuidDir, target)) - if err != nil { - return "", err - } - if dev == device { + + if rdev == trdev { return file.Name(), nil } }