github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/utils/utils.go (about)

     1  package utils
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"os/exec"
     9  	"strings"
    10  
    11  	"github.com/containers/storage/pkg/archive"
    12  	"github.com/pkg/errors"
    13  	"github.com/sirupsen/logrus"
    14  )
    15  
    16  // ExecCmd executes a command with args and returns its output as a string along
    17  // with an error, if any
    18  func ExecCmd(name string, args ...string) (string, error) {
    19  	cmd := exec.Command(name, args...)
    20  	var stdout bytes.Buffer
    21  	var stderr bytes.Buffer
    22  	cmd.Stdout = &stdout
    23  	cmd.Stderr = &stderr
    24  
    25  	err := cmd.Run()
    26  	if err != nil {
    27  		return "", fmt.Errorf("`%v %v` failed: %v %v (%v)", name, strings.Join(args, " "), stderr.String(), stdout.String(), err)
    28  	}
    29  
    30  	return stdout.String(), nil
    31  }
    32  
    33  // ExecCmdWithStdStreams execute a command with the specified standard streams.
    34  func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, env []string, name string, args ...string) error {
    35  	cmd := exec.Command(name, args...)
    36  	cmd.Stdin = stdin
    37  	cmd.Stdout = stdout
    38  	cmd.Stderr = stderr
    39  	if env != nil {
    40  		cmd.Env = env
    41  	}
    42  
    43  	err := cmd.Run()
    44  	if err != nil {
    45  		return fmt.Errorf("`%v %v` failed: %v", name, strings.Join(args, " "), err)
    46  	}
    47  
    48  	return nil
    49  }
    50  
    51  // ErrDetach is an error indicating that the user manually detached from the
    52  // container.
    53  var ErrDetach = errors.New("detached from container")
    54  
    55  // CopyDetachable is similar to io.Copy but support a detach key sequence to break out.
    56  func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {
    57  	buf := make([]byte, 32*1024)
    58  	for {
    59  		nr, er := src.Read(buf)
    60  		if nr > 0 {
    61  			preservBuf := []byte{}
    62  			for i, key := range keys {
    63  				preservBuf = append(preservBuf, buf[0:nr]...)
    64  				if nr != 1 || buf[0] != key {
    65  					break
    66  				}
    67  				if i == len(keys)-1 {
    68  					return 0, ErrDetach
    69  				}
    70  				nr, er = src.Read(buf)
    71  			}
    72  			var nw int
    73  			var ew error
    74  			if len(preservBuf) > 0 {
    75  				nw, ew = dst.Write(preservBuf)
    76  				nr = len(preservBuf)
    77  			} else {
    78  				nw, ew = dst.Write(buf[0:nr])
    79  			}
    80  			if nw > 0 {
    81  				written += int64(nw)
    82  			}
    83  			if ew != nil {
    84  				err = ew
    85  				break
    86  			}
    87  			if nr != nw {
    88  				err = io.ErrShortWrite
    89  				break
    90  			}
    91  		}
    92  		if er != nil {
    93  			if er != io.EOF {
    94  				err = er
    95  			}
    96  			break
    97  		}
    98  	}
    99  	return written, err
   100  }
   101  
   102  // UntarToFileSystem untars an os.file of a tarball to a destination in the filesystem
   103  func UntarToFileSystem(dest string, tarball *os.File, options *archive.TarOptions) error {
   104  	logrus.Debugf("untarring %s", tarball.Name())
   105  	return archive.Untar(tarball, dest, options)
   106  }
   107  
   108  // TarToFilesystem creates a tarball from source and writes to an os.file
   109  // provided
   110  func TarToFilesystem(source string, tarball *os.File) error {
   111  	tb, err := Tar(source)
   112  	if err != nil {
   113  		return err
   114  	}
   115  	_, err = io.Copy(tarball, tb)
   116  	if err != nil {
   117  		return err
   118  	}
   119  	logrus.Debugf("wrote tarball file %s", tarball.Name())
   120  	return nil
   121  }
   122  
   123  // Tar creates a tarball from source and returns a readcloser of it
   124  func Tar(source string) (io.ReadCloser, error) {
   125  	logrus.Debugf("creating tarball of %s", source)
   126  	return archive.Tar(source, archive.Uncompressed)
   127  }