123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- // +build !windows
- /*
- Copyright The containerd Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package proc
- import (
- "context"
- "fmt"
- "io"
- "os"
- "sync"
- "syscall"
- "github.com/containerd/fifo"
- runc "github.com/containerd/go-runc"
- )
- var bufPool = sync.Pool{
- New: func() interface{} {
- buffer := make([]byte, 32<<10)
- return &buffer
- },
- }
- func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) error {
- var sameFile io.WriteCloser
- for _, i := range []struct {
- name string
- dest func(wc io.WriteCloser, rc io.Closer)
- }{
- {
- name: stdout,
- dest: func(wc io.WriteCloser, rc io.Closer) {
- wg.Add(1)
- cwg.Add(1)
- go func() {
- cwg.Done()
- p := bufPool.Get().(*[]byte)
- defer bufPool.Put(p)
- io.CopyBuffer(wc, rio.Stdout(), *p)
- wg.Done()
- wc.Close()
- if rc != nil {
- rc.Close()
- }
- }()
- },
- }, {
- name: stderr,
- dest: func(wc io.WriteCloser, rc io.Closer) {
- wg.Add(1)
- cwg.Add(1)
- go func() {
- cwg.Done()
- p := bufPool.Get().(*[]byte)
- defer bufPool.Put(p)
- io.CopyBuffer(wc, rio.Stderr(), *p)
- wg.Done()
- wc.Close()
- if rc != nil {
- rc.Close()
- }
- }()
- },
- },
- } {
- ok, err := isFifo(i.name)
- if err != nil {
- return err
- }
- var (
- fw io.WriteCloser
- fr io.Closer
- )
- if ok {
- if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil {
- return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
- }
- if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil {
- return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
- }
- } else {
- if sameFile != nil {
- i.dest(sameFile, nil)
- continue
- }
- if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil {
- return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
- }
- if stdout == stderr {
- sameFile = fw
- }
- }
- i.dest(fw, fr)
- }
- if stdin == "" {
- rio.Stdin().Close()
- return nil
- }
- f, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0)
- if err != nil {
- return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err)
- }
- cwg.Add(1)
- go func() {
- cwg.Done()
- p := bufPool.Get().(*[]byte)
- defer bufPool.Put(p)
- io.CopyBuffer(rio.Stdin(), f, *p)
- rio.Stdin().Close()
- f.Close()
- }()
- return nil
- }
- // isFifo checks if a file is a fifo
- // if the file does not exist then it returns false
- func isFifo(path string) (bool, error) {
- stat, err := os.Stat(path)
- if err != nil {
- if os.IsNotExist(err) {
- return false, nil
- }
- return false, err
- }
- if stat.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
- return true, nil
- }
- return false, nil
- }
|