2017-02-01 00:45:59 +00:00
package devices
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"github.com/opencontainers/runc/libcontainer/configs"
2017-07-20 04:07:01 +00:00
"golang.org/x/sys/unix"
2017-02-01 00:45:59 +00:00
)
var (
ErrNotADevice = errors . New ( "not a device node" )
)
// Testing dependencies
var (
2017-08-05 11:40:46 +00:00
unixLstat = unix . Lstat
2017-02-01 00:45:59 +00:00
ioutilReadDir = ioutil . ReadDir
)
2017-02-06 20:16:36 +00:00
// Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct.
2017-02-01 00:45:59 +00:00
func DeviceFromPath ( path , permissions string ) ( * configs . Device , error ) {
2017-08-05 11:40:46 +00:00
var stat unix . Stat_t
err := unixLstat ( path , & stat )
2017-02-01 00:45:59 +00:00
if err != nil {
return nil , err
}
2018-01-19 21:37:10 +00:00
var (
devNumber = stat . Rdev
major = unix . Major ( devNumber )
)
if major == 0 {
return nil , ErrNotADevice
}
2017-02-01 00:45:59 +00:00
var (
2017-08-05 11:40:46 +00:00
devType rune
mode = stat . Mode
2017-02-01 00:45:59 +00:00
)
switch {
2017-08-05 11:40:46 +00:00
case mode & unix . S_IFBLK == unix . S_IFBLK :
devType = 'b'
case mode & unix . S_IFCHR == unix . S_IFCHR :
2017-02-01 00:45:59 +00:00
devType = 'c'
}
return & configs . Device {
Type : devType ,
Path : path ,
2018-01-19 21:37:10 +00:00
Major : int64 ( major ) ,
Minor : int64 ( unix . Minor ( devNumber ) ) ,
2017-02-01 00:45:59 +00:00
Permissions : permissions ,
2017-08-05 11:40:46 +00:00
FileMode : os . FileMode ( mode ) ,
2018-01-19 21:37:10 +00:00
Uid : stat . Uid ,
Gid : stat . Gid ,
2017-02-01 00:45:59 +00:00
} , nil
}
func HostDevices ( ) ( [ ] * configs . Device , error ) {
return getDevices ( "/dev" )
}
func getDevices ( path string ) ( [ ] * configs . Device , error ) {
files , err := ioutilReadDir ( path )
if err != nil {
return nil , err
}
out := [ ] * configs . Device { }
for _ , f := range files {
switch {
case f . IsDir ( ) :
switch f . Name ( ) {
2017-07-20 04:07:01 +00:00
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
case "pts" , "shm" , "fd" , "mqueue" , ".lxc" , ".lxd-mounts" :
2017-02-01 00:45:59 +00:00
continue
default :
sub , err := getDevices ( filepath . Join ( path , f . Name ( ) ) )
if err != nil {
return nil , err
}
out = append ( out , sub ... )
continue
}
case f . Name ( ) == "console" :
continue
}
device , err := DeviceFromPath ( filepath . Join ( path , f . Name ( ) ) , "rwm" )
if err != nil {
if err == ErrNotADevice {
continue
}
2017-02-06 20:16:36 +00:00
if os . IsNotExist ( err ) {
continue
}
2017-02-01 00:45:59 +00:00
return nil , err
}
out = append ( out , device )
}
return out , nil
}