github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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 //go:build linux 17 // +build linux 18 19 package shim 20 21 import ( 22 "context" 23 "fmt" 24 "io" 25 "sync" 26 27 "github.com/containerd/console" 28 "github.com/containerd/fifo" 29 "golang.org/x/sys/unix" 30 ) 31 32 type linuxPlatform struct { 33 epoller *console.Epoller 34 } 35 36 func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, wg *sync.WaitGroup) (console.Console, error) { 37 if p.epoller == nil { 38 return nil, fmt.Errorf("uninitialized epoller") 39 } 40 41 epollConsole, err := p.epoller.Add(console) 42 if err != nil { 43 return nil, err 44 } 45 46 if stdin != "" { 47 in, err := fifo.OpenFifo(context.Background(), stdin, unix.O_RDONLY|unix.O_NONBLOCK, 0) 48 if err != nil { 49 return nil, err 50 } 51 go func() { 52 p := bufPool.Get().(*[]byte) 53 defer bufPool.Put(p) 54 io.CopyBuffer(epollConsole, in, *p) 55 }() 56 } 57 58 outw, err := fifo.OpenFifo(ctx, stdout, unix.O_WRONLY, 0) 59 if err != nil { 60 return nil, err 61 } 62 outr, err := fifo.OpenFifo(ctx, stdout, unix.O_RDONLY, 0) 63 if err != nil { 64 return nil, err 65 } 66 wg.Add(1) 67 go func() { 68 p := bufPool.Get().(*[]byte) 69 defer bufPool.Put(p) 70 io.CopyBuffer(outw, epollConsole, *p) 71 epollConsole.Close() 72 outr.Close() 73 outw.Close() 74 wg.Done() 75 }() 76 return epollConsole, nil 77 } 78 79 func (p *linuxPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error { 80 if p.epoller == nil { 81 return fmt.Errorf("uninitialized epoller") 82 } 83 epollConsole, ok := cons.(*console.EpollConsole) 84 if !ok { 85 return fmt.Errorf("expected EpollConsole, got %#v", cons) 86 } 87 return epollConsole.Shutdown(p.epoller.CloseConsole) 88 } 89 90 func (p *linuxPlatform) Close() error { 91 return p.epoller.Close() 92 } 93 94 // initialize a single epoll fd to manage our consoles. `initPlatform` should 95 // only be called once. 96 func (s *service) initPlatform() error { 97 if s.platform != nil { 98 return nil 99 } 100 epoller, err := console.NewEpoller() 101 if err != nil { 102 return fmt.Errorf("failed to initialize epoller: %w", err) 103 } 104 s.platform = &linuxPlatform{ 105 epoller: epoller, 106 } 107 go epoller.Wait() 108 return nil 109 }