in packages/pty_linux.go [45:138]
func runWithPty(cmd *exec.Cmd) ([]byte, []byte, error) {
// Much of this logic was taken from, without the CGO stuff:
// https://golang.org/src/os/signal/signal_cgo_test.go
pty, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0)
if err != nil {
return nil, nil, err
}
defer pty.Close()
// grantpt doesn't appear to be required anymore.
// unlockpt
var i int
if err := ioctl(pty.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&i))); err != nil {
return nil, nil, fmt.Errorf("error from ioctl TIOCSPTLCK: %v", err)
}
// ptsname
var u uint32
if err := ioctl(pty.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != nil {
return nil, nil, fmt.Errorf("error from ioctl TIOCGPTN: %v", err)
}
path := filepath.Join("/dev/pts", strconv.Itoa(int(u)))
tty, err := os.OpenFile(path, os.O_RDWR|syscall.O_NOCTTY, 0)
if err != nil {
return nil, nil, err
}
defer tty.Close()
if err := unix.IoctlSetWinsize(int(pty.Fd()), syscall.TIOCSWINSZ, &unix.Winsize{Row: 1, Col: 500}); err != nil {
return nil, nil, fmt.Errorf("error from IoctlSetWinsize: %v", err)
}
var stderr bytes.Buffer
cmd.Stdin = tty
cmd.Stdout = tty
cmd.Stderr = &stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Setctty: true,
Setsid: true,
Ctty: 0, // Stdin of the child process
}
var stdout bytes.Buffer
var retErr error
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
input := bufio.NewReader(pty)
for {
b, err := input.ReadBytes('\n')
if err != nil {
if perr, ok := err.(*os.PathError); ok {
err = perr.Err
}
if err != io.EOF && err != syscall.EIO {
retErr = err
}
return
}
if _, err := stdout.Write(b); err != nil {
retErr = err
return
}
}
}()
cmdErr := cmd.Run()
if err := tty.Close(); err != nil {
return stdout.Bytes(), stderr.Bytes(), err
}
wg.Wait()
if cmdErr != nil {
// Yum returns non-zero exit values on non-error conditions.
// Errors which are *not* in this category indicate failure.
if _, ok := cmdErr.(*exec.ExitError); !ok {
return stdout.Bytes(), stderr.Bytes(), cmdErr
}
}
// Exit code 0 means no updates, 1 probably means there are but we just didn't install them.
if cmdErr == nil {
return nil, nil, nil
}
return stdout.Bytes(), stderr.Bytes(), retErr
}