github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/shim/service_linux.go (about) 1 // Copyright 2018 The containerd Authors. 2 // Copyright 2018 The gVisor Authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // https://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 // +build linux 17 18 package shim 19 20 import ( 21 "context" 22 "fmt" 23 "io" 24 "sync" 25 26 "github.com/containerd/console" 27 "github.com/containerd/fifo" 28 "golang.org/x/sys/unix" 29 ) 30 31 type linuxPlatform struct { 32 epoller *console.Epoller 33 } 34 35 func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, wg *sync.WaitGroup) (console.Console, error) { 36 if p.epoller == nil { 37 return nil, fmt.Errorf("uninitialized epoller") 38 } 39 40 epollConsole, err := p.epoller.Add(console) 41 if err != nil { 42 return nil, err 43 } 44 45 if stdin != "" { 46 in, err := fifo.OpenFifo(context.Background(), stdin, unix.O_RDONLY|unix.O_NONBLOCK, 0) 47 if err != nil { 48 return nil, err 49 } 50 go func() { 51 p := bufPool.Get().(*[]byte) 52 defer bufPool.Put(p) 53 io.CopyBuffer(epollConsole, in, *p) 54 }() 55 } 56 57 outw, err := fifo.OpenFifo(ctx, stdout, unix.O_WRONLY, 0) 58 if err != nil { 59 return nil, err 60 } 61 outr, err := fifo.OpenFifo(ctx, stdout, unix.O_RDONLY, 0) 62 if err != nil { 63 return nil, err 64 } 65 wg.Add(1) 66 go func() { 67 p := bufPool.Get().(*[]byte) 68 defer bufPool.Put(p) 69 io.CopyBuffer(outw, epollConsole, *p) 70 epollConsole.Close() 71 outr.Close() 72 outw.Close() 73 wg.Done() 74 }() 75 return epollConsole, nil 76 } 77 78 func (p *linuxPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error { 79 if p.epoller == nil { 80 return fmt.Errorf("uninitialized epoller") 81 } 82 epollConsole, ok := cons.(*console.EpollConsole) 83 if !ok { 84 return fmt.Errorf("expected EpollConsole, got %#v", cons) 85 } 86 return epollConsole.Shutdown(p.epoller.CloseConsole) 87 } 88 89 func (p *linuxPlatform) Close() error { 90 return p.epoller.Close() 91 } 92 93 // initialize a single epoll fd to manage our consoles. `initPlatform` should 94 // only be called once. 95 func (s *service) initPlatform() error { 96 if s.platform != nil { 97 return nil 98 } 99 epoller, err := console.NewEpoller() 100 if err != nil { 101 return fmt.Errorf("failed to initialize epoller: %w", err) 102 } 103 s.platform = &linuxPlatform{ 104 epoller: epoller, 105 } 106 go epoller.Wait() 107 return nil 108 }