mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2024-11-26 22:09:35 +00:00
175 lines
3.5 KiB
Go
175 lines
3.5 KiB
Go
|
package devices
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
Wildcard = -1
|
||
|
)
|
||
|
|
||
|
type Device struct {
|
||
|
Rule
|
||
|
|
||
|
// Path to the device.
|
||
|
Path string `json:"path"`
|
||
|
|
||
|
// FileMode permission bits for the device.
|
||
|
FileMode os.FileMode `json:"file_mode"`
|
||
|
|
||
|
// Uid of the device.
|
||
|
Uid uint32 `json:"uid"`
|
||
|
|
||
|
// Gid of the device.
|
||
|
Gid uint32 `json:"gid"`
|
||
|
}
|
||
|
|
||
|
// Permissions is a cgroupv1-style string to represent device access. It
|
||
|
// has to be a string for backward compatibility reasons, hence why it has
|
||
|
// methods to do set operations.
|
||
|
type Permissions string
|
||
|
|
||
|
const (
|
||
|
deviceRead uint = (1 << iota)
|
||
|
deviceWrite
|
||
|
deviceMknod
|
||
|
)
|
||
|
|
||
|
func (p Permissions) toSet() uint {
|
||
|
var set uint
|
||
|
for _, perm := range p {
|
||
|
switch perm {
|
||
|
case 'r':
|
||
|
set |= deviceRead
|
||
|
case 'w':
|
||
|
set |= deviceWrite
|
||
|
case 'm':
|
||
|
set |= deviceMknod
|
||
|
}
|
||
|
}
|
||
|
return set
|
||
|
}
|
||
|
|
||
|
func fromSet(set uint) Permissions {
|
||
|
var perm string
|
||
|
if set&deviceRead == deviceRead {
|
||
|
perm += "r"
|
||
|
}
|
||
|
if set&deviceWrite == deviceWrite {
|
||
|
perm += "w"
|
||
|
}
|
||
|
if set&deviceMknod == deviceMknod {
|
||
|
perm += "m"
|
||
|
}
|
||
|
return Permissions(perm)
|
||
|
}
|
||
|
|
||
|
// Union returns the union of the two sets of Permissions.
|
||
|
func (p Permissions) Union(o Permissions) Permissions {
|
||
|
lhs := p.toSet()
|
||
|
rhs := o.toSet()
|
||
|
return fromSet(lhs | rhs)
|
||
|
}
|
||
|
|
||
|
// Difference returns the set difference of the two sets of Permissions.
|
||
|
// In set notation, A.Difference(B) gives you A\B.
|
||
|
func (p Permissions) Difference(o Permissions) Permissions {
|
||
|
lhs := p.toSet()
|
||
|
rhs := o.toSet()
|
||
|
return fromSet(lhs &^ rhs)
|
||
|
}
|
||
|
|
||
|
// Intersection computes the intersection of the two sets of Permissions.
|
||
|
func (p Permissions) Intersection(o Permissions) Permissions {
|
||
|
lhs := p.toSet()
|
||
|
rhs := o.toSet()
|
||
|
return fromSet(lhs & rhs)
|
||
|
}
|
||
|
|
||
|
// IsEmpty returns whether the set of permissions in a Permissions is
|
||
|
// empty.
|
||
|
func (p Permissions) IsEmpty() bool {
|
||
|
return p == Permissions("")
|
||
|
}
|
||
|
|
||
|
// IsValid returns whether the set of permissions is a subset of valid
|
||
|
// permissions (namely, {r,w,m}).
|
||
|
func (p Permissions) IsValid() bool {
|
||
|
return p == fromSet(p.toSet())
|
||
|
}
|
||
|
|
||
|
type Type rune
|
||
|
|
||
|
const (
|
||
|
WildcardDevice Type = 'a'
|
||
|
BlockDevice Type = 'b'
|
||
|
CharDevice Type = 'c' // or 'u'
|
||
|
FifoDevice Type = 'p'
|
||
|
)
|
||
|
|
||
|
func (t Type) IsValid() bool {
|
||
|
switch t {
|
||
|
case WildcardDevice, BlockDevice, CharDevice, FifoDevice:
|
||
|
return true
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (t Type) CanMknod() bool {
|
||
|
switch t {
|
||
|
case BlockDevice, CharDevice, FifoDevice:
|
||
|
return true
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (t Type) CanCgroup() bool {
|
||
|
switch t {
|
||
|
case WildcardDevice, BlockDevice, CharDevice:
|
||
|
return true
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Rule struct {
|
||
|
// Type of device ('c' for char, 'b' for block). If set to 'a', this rule
|
||
|
// acts as a wildcard and all fields other than Allow are ignored.
|
||
|
Type Type `json:"type"`
|
||
|
|
||
|
// Major is the device's major number.
|
||
|
Major int64 `json:"major"`
|
||
|
|
||
|
// Minor is the device's minor number.
|
||
|
Minor int64 `json:"minor"`
|
||
|
|
||
|
// Permissions is the set of permissions that this rule applies to (in the
|
||
|
// cgroupv1 format -- any combination of "rwm").
|
||
|
Permissions Permissions `json:"permissions"`
|
||
|
|
||
|
// Allow specifies whether this rule is allowed.
|
||
|
Allow bool `json:"allow"`
|
||
|
}
|
||
|
|
||
|
func (d *Rule) CgroupString() string {
|
||
|
var (
|
||
|
major = strconv.FormatInt(d.Major, 10)
|
||
|
minor = strconv.FormatInt(d.Minor, 10)
|
||
|
)
|
||
|
if d.Major == Wildcard {
|
||
|
major = "*"
|
||
|
}
|
||
|
if d.Minor == Wildcard {
|
||
|
minor = "*"
|
||
|
}
|
||
|
return fmt.Sprintf("%c %s:%s %s", d.Type, major, minor, d.Permissions)
|
||
|
}
|
||
|
|
||
|
func (d *Rule) Mkdev() (uint64, error) {
|
||
|
return mkDev(d)
|
||
|
}
|