2014-02-18 07:14:30 +08:00
package devices
import (
2014-05-31 09:30:27 +08:00
"errors"
2014-02-18 07:14:30 +08:00
"fmt"
2014-05-31 09:30:27 +08:00
"io/ioutil"
2014-02-18 07:14:30 +08:00
"os"
2014-05-31 09:30:27 +08:00
"path/filepath"
2017-05-10 05:38:27 +08:00
"syscall" //only for Stat_t
2014-02-18 07:14:30 +08:00
2015-06-22 10:29:59 +08:00
"github.com/opencontainers/runc/libcontainer/configs"
2017-05-10 05:38:27 +08:00
"golang.org/x/sys/unix"
2014-02-18 07:14:30 +08:00
)
2014-05-31 09:30:27 +08:00
var (
2015-02-01 11:56:27 +08:00
ErrNotADevice = errors . New ( "not a device node" )
2014-05-31 09:30:27 +08:00
)
2014-09-05 07:34:34 +08:00
// Testing dependencies
var (
2014-09-05 08:00:09 +08:00
osLstat = os . Lstat
ioutilReadDir = ioutil . ReadDir
2014-09-05 07:34:34 +08:00
)
2016-12-01 16:48:09 +08: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.
2015-02-01 11:56:27 +08:00
func DeviceFromPath ( path , permissions string ) ( * configs . Device , error ) {
2014-09-05 07:34:34 +08:00
fileInfo , err := osLstat ( path )
2014-05-31 09:30:27 +08:00
if err != nil {
return nil , err
}
2014-02-18 07:14:30 +08:00
var (
devType rune
2014-05-31 09:30:27 +08:00
mode = fileInfo . Mode ( )
fileModePermissionBits = os . FileMode . Perm ( mode )
2014-02-18 07:14:30 +08:00
)
switch {
2014-05-31 09:30:27 +08:00
case mode & os . ModeDevice == 0 :
2015-02-01 11:56:27 +08:00
return nil , ErrNotADevice
2014-05-31 09:30:27 +08:00
case mode & os . ModeCharDevice != 0 :
2017-05-10 05:38:27 +08:00
fileModePermissionBits |= unix . S_IFCHR
2014-02-18 07:14:30 +08:00
devType = 'c'
default :
2017-05-10 05:38:27 +08:00
fileModePermissionBits |= unix . S_IFBLK
2014-02-18 07:14:30 +08:00
devType = 'b'
}
2014-05-31 09:30:27 +08:00
stat_t , ok := fileInfo . Sys ( ) . ( * syscall . Stat_t )
2014-02-18 07:14:30 +08:00
if ! ok {
2014-05-31 09:30:27 +08:00
return nil , fmt . Errorf ( "cannot determine the device number for device %s" , path )
2014-02-18 07:14:30 +08:00
}
2014-05-31 09:30:27 +08:00
devNumber := int ( stat_t . Rdev )
2015-02-01 11:56:27 +08:00
return & configs . Device {
Type : devType ,
Path : path ,
Major : Major ( devNumber ) ,
Minor : Minor ( devNumber ) ,
Permissions : permissions ,
FileMode : fileModePermissionBits ,
Uid : stat_t . Uid ,
Gid : stat_t . Gid ,
2014-05-31 09:30:27 +08:00
} , nil
2014-02-18 07:14:30 +08:00
}
2015-02-01 11:56:27 +08:00
func HostDevices ( ) ( [ ] * configs . Device , error ) {
2015-02-04 09:44:58 +08:00
return getDevices ( "/dev" )
2014-05-31 09:30:27 +08:00
}
2015-02-04 09:44:58 +08:00
func getDevices ( path string ) ( [ ] * configs . Device , error ) {
2014-09-05 08:00:09 +08:00
files , err := ioutilReadDir ( path )
2014-05-31 09:30:27 +08:00
if err != nil {
return nil , err
2014-02-18 07:14:30 +08:00
}
2015-02-01 11:56:27 +08:00
out := [ ] * configs . Device { }
2014-05-31 09:30:27 +08:00
for _ , f := range files {
2014-10-25 02:04:20 +08:00
switch {
case f . IsDir ( ) :
2014-05-31 09:30:27 +08:00
switch f . Name ( ) {
2017-03-08 23:25:10 +08:00
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
2017-02-15 02:27:26 +08:00
case "pts" , "shm" , "fd" , "mqueue" , ".lxc" , ".lxd-mounts" :
2014-05-31 09:30:27 +08:00
continue
default :
2015-02-04 09:44:58 +08:00
sub , err := getDevices ( filepath . Join ( path , f . Name ( ) ) )
2014-05-31 09:30:27 +08:00
if err != nil {
return nil , err
}
out = append ( out , sub ... )
continue
}
2014-10-25 02:04:20 +08:00
case f . Name ( ) == "console" :
continue
2014-05-31 09:30:27 +08:00
}
2015-02-01 11:56:27 +08:00
device , err := DeviceFromPath ( filepath . Join ( path , f . Name ( ) ) , "rwm" )
2014-10-25 02:04:20 +08:00
if err != nil {
2015-02-01 11:56:27 +08:00
if err == ErrNotADevice {
2014-10-25 02:04:20 +08:00
continue
2014-05-31 09:30:27 +08:00
}
2016-12-08 03:08:00 +08:00
if os . IsNotExist ( err ) {
continue
}
2014-10-25 02:04:20 +08:00
return nil , err
2014-05-31 09:30:27 +08:00
}
2014-10-25 02:04:20 +08:00
out = append ( out , device )
2014-05-31 09:30:27 +08:00
}
return out , nil
}