Skip to content
This repository has been archived by the owner on Feb 24, 2020. It is now read-only.

Commit

Permalink
pkg/fileutil: helper function to get major, minor numbers of a device…
Browse files Browse the repository at this point in the history
… file.
  • Loading branch information
Casey Callendrello authored and Casey Callendrello committed Jan 5, 2017
1 parent ed4829e commit 7033fb5
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
37 changes: 37 additions & 0 deletions pkg/fileutil/fileutil_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package fileutil

import (
"fmt"
"os"
"syscall"
"unsafe"
Expand Down Expand Up @@ -105,3 +106,39 @@ func Lsetxattr(path string, attr string, data []byte, flags int) error {
}
return nil
}

// GetDeviceInfo returns the type, major, and minor numbers of a device.
// Kind is 'b' or 'c' for block and character devices, respectively.
// This does not follow symlinks.
func GetDeviceInfo(path string) (kind rune, major uint64, minor uint64, err error) {
d, err := os.Lstat(path)
if err != nil {
return
}
mode := d.Mode()

if mode&os.ModeDevice == 0 {
err = fmt.Errorf("not a device: %s", path)
return
}
stat_t, ok := d.Sys().(*syscall.Stat_t)
if !ok {
err = fmt.Errorf("cannot determine device number")
return
}
return getDeviceInfo(mode, stat_t.Rdev)
}

// Parse the device info out of the mode bits. Separate for testability.
func getDeviceInfo(mode os.FileMode, rdev uint64) (kind rune, major uint64, minor uint64, err error) {
kind = 'b'

if mode&os.ModeCharDevice != 0 {
kind = 'c'
}

major = (rdev >> 8) & 0xfff
minor = (rdev & 0xff) | ((rdev >> 12) & 0xfff00)

return
}
78 changes: 78 additions & 0 deletions pkg/fileutil/fileutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,81 @@ func TestFileIsExecutable(t *testing.T) {
}
}
}

func TestDeviceInfo(t *testing.T) {
// First, test the main call
{
kind, major, minor, err := GetDeviceInfo("/dev/null")
if kind != 'c' || major != 1 || minor != 3 || err != nil {
t.Errorf("GetDeviceInfo(/dev/null) wrong result")
}
}

{
_, _, _, err := GetDeviceInfo("/usr")
if err == nil {
t.Errorf("GetDeviceInfo(/usr) should return err")
}
}

// Then test the logic more specifically
for i, tt := range []struct {
mode os.FileMode
rdev uint64
kind rune
major uint64
minor uint64
}{
// /dev/null
{
69206454,
259,
'c',
1,
3,
},
// /dev/sda1
{
67109296,
2049,
'b',
8,
1,
},
// /dev/pts/3
{
69206416,
34819,
'c',
136,
3,
},
// /dev/dm-0
{
67109296,
64768,
'b',
253,
0,
},
} {
kind, major, minor, err := getDeviceInfo(tt.mode, tt.rdev)
if err != nil {
t.Errorf("getDeviceInfo %d not as expected, got err %s", i, err)
}
// don't care about result when err
if err != nil {
continue
}

if tt.kind != kind {
t.Errorf("getDeviceInfo %d kind expected %v got %v", i, tt.kind, kind)
}
if tt.major != major {
t.Errorf("getDeviceInfo %d major expected %v got %v", i, tt.major, major)
}
if tt.minor != minor {
t.Errorf("getDeviceInfo %d minor expected %v got %v", i, tt.minor, minor)
}
}
}

0 comments on commit 7033fb5

Please sign in to comment.