mirror of https://github.com/containers/podman.git
				
				
				
			
		
			
				
	
	
		
			141 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
package utils
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os/exec"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	systemdDbus "github.com/coreos/go-systemd/dbus"
 | 
						|
	"github.com/godbus/dbus"
 | 
						|
)
 | 
						|
 | 
						|
// ExecCmd executes a command with args and returns its output as a string along
 | 
						|
// with an error, if any
 | 
						|
func ExecCmd(name string, args ...string) (string, error) {
 | 
						|
	cmd := exec.Command(name, args...)
 | 
						|
	var stdout bytes.Buffer
 | 
						|
	var stderr bytes.Buffer
 | 
						|
	cmd.Stdout = &stdout
 | 
						|
	cmd.Stderr = &stderr
 | 
						|
 | 
						|
	err := cmd.Run()
 | 
						|
	if err != nil {
 | 
						|
		return "", fmt.Errorf("`%v %v` failed: %v %v (%v)", name, strings.Join(args, " "), stderr.String(), stdout.String(), err)
 | 
						|
	}
 | 
						|
 | 
						|
	return stdout.String(), nil
 | 
						|
}
 | 
						|
 | 
						|
// ExecCmdWithStdStreams execute a command with the specified standard streams.
 | 
						|
func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, name string, args ...string) error {
 | 
						|
	cmd := exec.Command(name, args...)
 | 
						|
	cmd.Stdin = stdin
 | 
						|
	cmd.Stdout = stdout
 | 
						|
	cmd.Stderr = stderr
 | 
						|
 | 
						|
	err := cmd.Run()
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("`%v %v` failed: %v", name, strings.Join(args, " "), err)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// StatusToExitCode converts wait status code to an exit code
 | 
						|
func StatusToExitCode(status int) int {
 | 
						|
	return ((status) & 0xff00) >> 8
 | 
						|
}
 | 
						|
 | 
						|
// RunUnderSystemdScope adds the specified pid to a systemd scope
 | 
						|
func RunUnderSystemdScope(pid int, slice string, unitName string) error {
 | 
						|
	var properties []systemdDbus.Property
 | 
						|
	conn, err := systemdDbus.New()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	properties = append(properties, systemdDbus.PropSlice(slice))
 | 
						|
	properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
 | 
						|
	properties = append(properties, newProp("Delegate", true))
 | 
						|
	properties = append(properties, newProp("DefaultDependencies", false))
 | 
						|
	ch := make(chan string)
 | 
						|
	_, err = conn.StartTransientUnit(unitName, "replace", properties, ch)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer conn.Close()
 | 
						|
 | 
						|
	// Block until job is started
 | 
						|
	<-ch
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func newProp(name string, units interface{}) systemdDbus.Property {
 | 
						|
	return systemdDbus.Property{
 | 
						|
		Name:  name,
 | 
						|
		Value: dbus.MakeVariant(units),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// DetachError is special error which returned in case of container detach.
 | 
						|
type DetachError struct{}
 | 
						|
 | 
						|
func (DetachError) Error() string {
 | 
						|
	return "detached from container"
 | 
						|
}
 | 
						|
 | 
						|
// CopyDetachable is similar to io.Copy but support a detach key sequence to break out.
 | 
						|
func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {
 | 
						|
	if len(keys) == 0 {
 | 
						|
		// Default keys : ctrl-p ctrl-q
 | 
						|
		keys = []byte{16, 17}
 | 
						|
	}
 | 
						|
 | 
						|
	buf := make([]byte, 32*1024)
 | 
						|
	for {
 | 
						|
		nr, er := src.Read(buf)
 | 
						|
		if nr > 0 {
 | 
						|
			preservBuf := []byte{}
 | 
						|
			for i, key := range keys {
 | 
						|
				preservBuf = append(preservBuf, buf[0:nr]...)
 | 
						|
				if nr != 1 || buf[0] != key {
 | 
						|
					break
 | 
						|
				}
 | 
						|
				if i == len(keys)-1 {
 | 
						|
					// src.Close()
 | 
						|
					return 0, DetachError{}
 | 
						|
				}
 | 
						|
				nr, er = src.Read(buf)
 | 
						|
			}
 | 
						|
			var nw int
 | 
						|
			var ew error
 | 
						|
			if len(preservBuf) > 0 {
 | 
						|
				nw, ew = dst.Write(preservBuf)
 | 
						|
				nr = len(preservBuf)
 | 
						|
			} else {
 | 
						|
				nw, ew = dst.Write(buf[0:nr])
 | 
						|
			}
 | 
						|
			if nw > 0 {
 | 
						|
				written += int64(nw)
 | 
						|
			}
 | 
						|
			if ew != nil {
 | 
						|
				err = ew
 | 
						|
				break
 | 
						|
			}
 | 
						|
			if nr != nw {
 | 
						|
				err = io.ErrShortWrite
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if er != nil {
 | 
						|
			if er != io.EOF {
 | 
						|
				err = er
 | 
						|
			}
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return written, err
 | 
						|
}
 |