github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/oci/spec_opts_unix.go (about) 1 // +build !linux,!windows 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package oci 20 21 import ( 22 "context" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 27 "github.com/containerd/containerd/containers" 28 specs "github.com/opencontainers/runtime-spec/specs-go" 29 "golang.org/x/sys/unix" 30 ) 31 32 // WithHostDevices adds all the hosts device nodes to the container's spec 33 func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { 34 setLinux(s) 35 36 devs, err := getDevices("/dev") 37 if err != nil { 38 return err 39 } 40 s.Linux.Devices = append(s.Linux.Devices, devs...) 41 return nil 42 } 43 44 func getDevices(path string) ([]specs.LinuxDevice, error) { 45 files, err := ioutil.ReadDir(path) 46 if err != nil { 47 return nil, err 48 } 49 var out []specs.LinuxDevice 50 for _, f := range files { 51 switch { 52 case f.IsDir(): 53 switch f.Name() { 54 // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 55 // ".udev" added to address https://github.com/opencontainers/runc/issues/2093 56 case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev": 57 continue 58 default: 59 sub, err := getDevices(filepath.Join(path, f.Name())) 60 if err != nil { 61 return nil, err 62 } 63 64 out = append(out, sub...) 65 continue 66 } 67 case f.Name() == "console": 68 continue 69 } 70 device, err := deviceFromPath(filepath.Join(path, f.Name()), "rwm") 71 if err != nil { 72 if err == ErrNotADevice { 73 continue 74 } 75 if os.IsNotExist(err) { 76 continue 77 } 78 return nil, err 79 } 80 out = append(out, *device) 81 } 82 return out, nil 83 } 84 85 func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) { 86 var stat unix.Stat_t 87 if err := unix.Lstat(path, &stat); err != nil { 88 return nil, err 89 } 90 91 var ( 92 devNumber = uint64(stat.Rdev) 93 major = unix.Major(devNumber) 94 minor = unix.Minor(devNumber) 95 ) 96 if major == 0 { 97 return nil, ErrNotADevice 98 } 99 100 var ( 101 devType string 102 mode = stat.Mode 103 ) 104 switch { 105 case mode&unix.S_IFBLK == unix.S_IFBLK: 106 devType = "b" 107 case mode&unix.S_IFCHR == unix.S_IFCHR: 108 devType = "c" 109 } 110 fm := os.FileMode(mode) 111 return &specs.LinuxDevice{ 112 Type: devType, 113 Path: path, 114 Major: int64(major), 115 Minor: int64(minor), 116 FileMode: &fm, 117 UID: &stat.Uid, 118 GID: &stat.Gid, 119 }, nil 120 } 121 122 // WithCPUCFS sets the container's Completely fair scheduling (CFS) quota and period 123 func WithCPUCFS(quota int64, period uint64) SpecOpts { 124 return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { 125 return nil 126 } 127 }