github.com/containerd/Containerd@v1.4.13/runtime/v2/shim/util_unix.go (about) 1 // +build !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 shim 20 21 import ( 22 "context" 23 "crypto/sha256" 24 "fmt" 25 "net" 26 "os" 27 "path/filepath" 28 "strings" 29 "syscall" 30 "time" 31 32 "github.com/containerd/containerd/namespaces" 33 "github.com/containerd/containerd/pkg/dialer" 34 "github.com/containerd/containerd/sys" 35 "github.com/pkg/errors" 36 ) 37 38 const ( 39 shimBinaryFormat = "containerd-shim-%s-%s" 40 socketPathLimit = 106 41 ) 42 43 func getSysProcAttr() *syscall.SysProcAttr { 44 return &syscall.SysProcAttr{ 45 Setpgid: true, 46 } 47 } 48 49 // SetScore sets the oom score for a process 50 func SetScore(pid int) error { 51 return sys.SetOOMScore(pid, sys.OOMScoreMaxKillable) 52 } 53 54 // AdjustOOMScore sets the OOM score for the process to the parents OOM score +1 55 // to ensure that they parent has a lower* score than the shim 56 // if not already at the maximum OOM Score 57 func AdjustOOMScore(pid int) error { 58 parent := os.Getppid() 59 score, err := sys.GetOOMScoreAdj(parent) 60 if err != nil { 61 return errors.Wrap(err, "get parent OOM score") 62 } 63 shimScore := score + 1 64 if shimScore > sys.OOMScoreAdjMax { 65 shimScore = sys.OOMScoreAdjMax 66 } 67 if err := sys.SetOOMScore(pid, shimScore); err != nil { 68 return errors.Wrap(err, "set shim OOM score") 69 } 70 return nil 71 } 72 73 const socketRoot = "/run/containerd" 74 75 // SocketAddress returns a socket address 76 func SocketAddress(ctx context.Context, socketPath, id string) (string, error) { 77 ns, err := namespaces.NamespaceRequired(ctx) 78 if err != nil { 79 return "", err 80 } 81 d := sha256.Sum256([]byte(filepath.Join(socketPath, ns, id))) 82 return fmt.Sprintf("unix://%s/%x", filepath.Join(socketRoot, "s"), d), nil 83 } 84 85 // AnonDialer returns a dialer for a socket 86 func AnonDialer(address string, timeout time.Duration) (net.Conn, error) { 87 return dialer.Dialer(socket(address).path(), timeout) 88 } 89 90 func AnonReconnectDialer(address string, timeout time.Duration) (net.Conn, error) { 91 return AnonDialer(address, timeout) 92 } 93 94 // NewSocket returns a new socket 95 func NewSocket(address string) (*net.UnixListener, error) { 96 var ( 97 sock = socket(address) 98 path = sock.path() 99 ) 100 if !sock.isAbstract() { 101 if err := os.MkdirAll(filepath.Dir(path), 0600); err != nil { 102 return nil, errors.Wrapf(err, "%s", path) 103 } 104 } 105 l, err := net.Listen("unix", path) 106 if err != nil { 107 return nil, err 108 } 109 if err := os.Chmod(path, 0600); err != nil { 110 os.Remove(sock.path()) 111 l.Close() 112 return nil, err 113 } 114 return l.(*net.UnixListener), nil 115 } 116 117 const abstractSocketPrefix = "\x00" 118 119 type socket string 120 121 func (s socket) isAbstract() bool { 122 return !strings.HasPrefix(string(s), "unix://") 123 } 124 125 func (s socket) path() string { 126 path := strings.TrimPrefix(string(s), "unix://") 127 // if there was no trim performed, we assume an abstract socket 128 if len(path) == len(s) { 129 path = abstractSocketPrefix + path 130 } 131 return path 132 } 133 134 // RemoveSocket removes the socket at the specified address if 135 // it exists on the filesystem 136 func RemoveSocket(address string) error { 137 sock := socket(address) 138 if !sock.isAbstract() { 139 return os.Remove(sock.path()) 140 } 141 return nil 142 } 143 144 // SocketEaddrinuse returns true if the provided error is caused by the 145 // EADDRINUSE error number 146 func SocketEaddrinuse(err error) bool { 147 netErr, ok := err.(*net.OpError) 148 if !ok { 149 return false 150 } 151 if netErr.Op != "listen" { 152 return false 153 } 154 syscallErr, ok := netErr.Err.(*os.SyscallError) 155 if !ok { 156 return false 157 } 158 errno, ok := syscallErr.Err.(syscall.Errno) 159 if !ok { 160 return false 161 } 162 return errno == syscall.EADDRINUSE 163 } 164 165 // CanConnect returns true if the socket provided at the address 166 // is accepting new connections 167 func CanConnect(address string) bool { 168 conn, err := AnonDialer(address, 100*time.Millisecond) 169 if err != nil { 170 return false 171 } 172 conn.Close() 173 return true 174 }