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