You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.1 KiB
Go
144 lines
4.1 KiB
Go
//go:build linux
|
|
|
|
package dap
|
|
|
|
// Ported from https://github.com/ktock/buildg/blob/v0.4.1/pkg/dap/dap.go
|
|
// Copyright The buildg Authors.
|
|
// Licensed under the Apache License, Version 2.0
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"path/filepath"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/containerd/console"
|
|
"github.com/containerd/fifo"
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
func AttachContainerIO(root string, stdin io.Reader, stdout, stderr io.Writer, setTtyRaw bool) error {
|
|
if root == "" {
|
|
return errors.Errorf("root needs to be specified")
|
|
}
|
|
|
|
type ioSet struct {
|
|
stdin io.WriteCloser
|
|
stdout io.ReadCloser
|
|
stderr io.ReadCloser
|
|
}
|
|
ioSetCh := make(chan ioSet)
|
|
errCh := make(chan error)
|
|
go func() {
|
|
stdin, stdout, stderr, err := openFifosClient(context.TODO(), root)
|
|
if err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
ioSetCh <- ioSet{stdin, stdout, stderr}
|
|
}()
|
|
var (
|
|
pStdin io.WriteCloser
|
|
pStdout io.ReadCloser
|
|
pStderr io.ReadCloser
|
|
)
|
|
select {
|
|
case ioSet := <-ioSetCh:
|
|
pStdin, pStdout, pStderr = ioSet.stdin, ioSet.stdout, ioSet.stderr
|
|
case err := <-errCh:
|
|
return err
|
|
case <-time.After(3 * time.Second):
|
|
return errors.Errorf("i/o timeout; check server is up and running")
|
|
}
|
|
defer func() { pStdin.Close(); pStdout.Close(); pStderr.Close() }()
|
|
|
|
if setTtyRaw {
|
|
con := console.Current()
|
|
if err := con.SetRaw(); err != nil {
|
|
return errors.Errorf("failed to configure terminal: %v", err)
|
|
}
|
|
defer con.Reset()
|
|
}
|
|
|
|
go io.Copy(pStdin, stdin)
|
|
eg, _ := errgroup.WithContext(context.TODO())
|
|
eg.Go(func() error { _, err := io.Copy(stdout, pStdout); return err })
|
|
eg.Go(func() error { _, err := io.Copy(stderr, pStderr); return err })
|
|
if err := eg.Wait(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(stderr, "exec finished\n")
|
|
return nil
|
|
}
|
|
|
|
func serveContainerIO(ctx context.Context, root string) (io.ReadCloser, io.WriteCloser, io.WriteCloser, func(), error) {
|
|
stdin, stdout, stderr, err := openFifosServer(ctx, root)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, err
|
|
}
|
|
return stdin, stdout, stderr, func() {
|
|
stdin.Close()
|
|
stdout.Close()
|
|
stderr.Close()
|
|
}, nil
|
|
}
|
|
|
|
func openFifosClient(ctx context.Context, fifosDir string) (stdin io.WriteCloser, stdout, stderr io.ReadCloser, retErr error) {
|
|
if stdin, retErr = fifo.OpenFifo(ctx, filepath.Join(fifosDir, "stdin"), syscall.O_WRONLY, 0700); retErr != nil {
|
|
return nil, nil, nil, errors.Errorf("failed to open stdin fifo: %v", retErr)
|
|
}
|
|
defer func() {
|
|
if retErr != nil && stdin != nil {
|
|
stdin.Close()
|
|
}
|
|
}()
|
|
if stdout, retErr = fifo.OpenFifo(ctx, filepath.Join(fifosDir, "stdout"), syscall.O_RDONLY, 0700); retErr != nil {
|
|
return nil, nil, nil, errors.Errorf("failed to open stdout fifo: %v", retErr)
|
|
}
|
|
defer func() {
|
|
if retErr != nil && stdout != nil {
|
|
stdout.Close()
|
|
}
|
|
}()
|
|
if stderr, retErr = fifo.OpenFifo(ctx, filepath.Join(fifosDir, "stderr"), syscall.O_RDONLY, 0700); retErr != nil {
|
|
return nil, nil, nil, errors.Errorf("failed to open stderr fifo: %v", retErr)
|
|
}
|
|
defer func() {
|
|
if retErr != nil && stderr != nil {
|
|
stderr.Close()
|
|
}
|
|
}()
|
|
return stdin, stdout, stderr, nil
|
|
}
|
|
|
|
func openFifosServer(ctx context.Context, fifosDir string) (stdin io.ReadCloser, stdout, stderr io.WriteCloser, retErr error) {
|
|
if stdin, retErr = fifo.OpenFifo(ctx, filepath.Join(fifosDir, "stdin"), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
|
|
return nil, nil, nil, errors.Errorf("failed to open stdin fifo: %v", retErr)
|
|
}
|
|
defer func() {
|
|
if retErr != nil && stdin != nil {
|
|
stdin.Close()
|
|
}
|
|
}()
|
|
if stdout, retErr = fifo.OpenFifo(ctx, filepath.Join(fifosDir, "stdout"), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
|
|
return nil, nil, nil, errors.Errorf("failed to open stdout fifo: %v", retErr)
|
|
}
|
|
defer func() {
|
|
if retErr != nil && stdout != nil {
|
|
stdout.Close()
|
|
}
|
|
}()
|
|
if stderr, retErr = fifo.OpenFifo(ctx, filepath.Join(fifosDir, "stderr"), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
|
|
return nil, nil, nil, errors.Errorf("failed to open stderr fifo: %v", retErr)
|
|
}
|
|
defer func() {
|
|
if retErr != nil && stderr != nil {
|
|
stderr.Close()
|
|
}
|
|
}()
|
|
return stdin, stdout, stderr, nil
|
|
}
|