run.go 1.4 KB

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