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 }