1//go:build !windows 2//+build !windows 3 4package pty 5 6import ( 7 "os" 8 "os/exec" 9 "syscall" 10) 11 12// Start assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, 13// and c.Stderr, calls c.Start, and returns the File of the tty's 14// corresponding pty. 15// 16// Starts the process in a new session and sets the controlling terminal. 17func Start(cmd *exec.Cmd) (*os.File, error) { 18 return StartWithSize(cmd, nil) 19} 20 21// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, 22// and c.Stderr, calls c.Start, and returns the File of the tty's 23// corresponding pty. 24// 25// This will resize the pty to the specified size before starting the command. 26// Starts the process in a new session and sets the controlling terminal. 27func StartWithSize(cmd *exec.Cmd, ws *Winsize) (*os.File, error) { 28 if cmd.SysProcAttr == nil { 29 cmd.SysProcAttr = &syscall.SysProcAttr{} 30 } 31 cmd.SysProcAttr.Setsid = true 32 cmd.SysProcAttr.Setctty = true 33 return StartWithAttrs(cmd, ws, cmd.SysProcAttr) 34} 35 36// StartWithAttrs assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, 37// and c.Stderr, calls c.Start, and returns the File of the tty's 38// corresponding pty. 39// 40// This will resize the pty to the specified size before starting the command if a size is provided. 41// The `attrs` parameter overrides the one set in c.SysProcAttr. 42// 43// This should generally not be needed. Used in some edge cases where it is needed to create a pty 44// without a controlling terminal. 45func StartWithAttrs(c *exec.Cmd, sz *Winsize, attrs *syscall.SysProcAttr) (*os.File, error) { 46 pty, tty, err := Open() 47 if err != nil { 48 return nil, err 49 } 50 defer func() { _ = tty.Close() }() // Best effort. 51 52 if sz != nil { 53 if err := Setsize(pty, sz); err != nil { 54 _ = pty.Close() // Best effort. 55 return nil, err 56 } 57 } 58 if c.Stdout == nil { 59 c.Stdout = tty 60 } 61 if c.Stderr == nil { 62 c.Stderr = tty 63 } 64 if c.Stdin == nil { 65 c.Stdin = tty 66 } 67 68 c.SysProcAttr = attrs 69 70 if err := c.Start(); err != nil { 71 _ = pty.Close() // Best effort. 72 return nil, err 73 } 74 return pty, err 75} 76