aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJim Porter2022-07-17 20:25:00 -0700
committerJim Porter2022-08-05 17:58:54 -0700
commitd7b89ea4077d4fe677ba0577245328819ee79cdc (patch)
treed4e499042bdf2f301be7f2d7ec05f0d1bfd8d44b /src
parentb70369c557efed3dcd86dc64a2e73e3480dea6af (diff)
downloademacs-d7b89ea4077d4fe677ba0577245328819ee79cdc.tar.gz
emacs-d7b89ea4077d4fe677ba0577245328819ee79cdc.zip
Allow creating processes where only one of stdin or stdout is a PTY
* src/lisp.h (emacs_spawn): * src/callproc.c (emacs_spawn): Add PTY_IN and PTY_OUT arguments to specify which streams should be set up as a PTY. (call_process): Adjust call to 'emacs_spawn'. * src/process.h (Lisp_Process): Replace 'pty_flag' with 'pty_in' and 'pty_out'. * src/process.c (is_pty_from_symbol): New function. (make-process): Allow :connection-type to be a cons cell, and allow using a stderr process with a PTY for stdin/stdout. (create_process): Handle creating a process where only one of stdin or stdout is a PTY. * lisp/eshell/esh-proc.el (eshell-needs-pipe, eshell-needs-pipe-p): Remove. (eshell-gather-process-output): Use 'make-process' and set ':connection-type' as needed by the value of 'eshell-in-pipeline-p'. * lisp/net/tramp.el (tramp-handle-make-process): * lisp/net/tramp-adb.el (tramp-adb-handle-make-process): * lisp/net/tramp-sh.el (tramp-sh-handle-make-process): Don't signal an error when ':connection-type' is a cons cell. * test/src/process-tests.el (process-test-sentinel-wait-function-working-p): Allow passing PROC in, and rework into... (process-test-wait-for-sentinel): ... this. (process-test-sentinel-accept-process-output) (process-test-sentinel-sit-for, process-test-quoted-batfile) (process-test-stderr-filter): Use 'process-test-wait-for-sentinel'. (make/process/test-connection-type): New function. (make-process/connection-type/pty, make-process/connection-type/pty-2) (make-process/connection-type/pipe) (make-process/connection-type/pipe-2) (make-process/connection-type/in-pty) (make-process/connection-type/out-pty) (make-process/connection-type/pty-with-stderr-buffer) (make-process/connection-type/out-pty-with-stderr-buffer): New tests. * test/lisp/eshell/esh-proc-tests.el (esh-proc-test--detect-pty-cmd): New variable. (esh-proc-test/pipeline-connection-type/no-pipeline) (esh-proc-test/pipeline-connection-type/first) (esh-proc-test/pipeline-connection-type/middle) (esh-proc-test/pipeline-connection-type/last): New tests. * doc/lispref/processes.texi (Asynchronous Processes): Document new ':connection-type' behavior. (Output from Processes): Remove caveat about ':stderr' forcing 'make-process' to use pipes. * etc/NEWS: Announce this change (bug#56025).
Diffstat (limited to 'src')
-rw-r--r--src/callproc.c37
-rw-r--r--src/lisp.h3
-rw-r--r--src/process.c129
-rw-r--r--src/process.h5
4 files changed, 107 insertions, 67 deletions
diff --git a/src/callproc.c b/src/callproc.c
index dd162f36a6c..aec0a2f5a58 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -650,7 +650,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
650 650
651 child_errno 651 child_errno
652 = emacs_spawn (&pid, filefd, fd_output, fd_error, new_argv, env, 652 = emacs_spawn (&pid, filefd, fd_output, fd_error, new_argv, env,
653 SSDATA (current_dir), NULL, &oldset); 653 SSDATA (current_dir), NULL, false, false, &oldset);
654 eassert ((child_errno == 0) == (0 < pid)); 654 eassert ((child_errno == 0) == (0 < pid));
655 655
656 if (pid > 0) 656 if (pid > 0)
@@ -1412,14 +1412,15 @@ emacs_posix_spawn_init_attributes (posix_spawnattr_t *attributes,
1412int 1412int
1413emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, 1413emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1414 char **argv, char **envp, const char *cwd, 1414 char **argv, char **envp, const char *cwd,
1415 const char *pty, const sigset_t *oldset) 1415 const char *pty_name, bool pty_in, bool pty_out,
1416 const sigset_t *oldset)
1416{ 1417{
1417#if USABLE_POSIX_SPAWN 1418#if USABLE_POSIX_SPAWN
1418 /* Prefer the simpler `posix_spawn' if available. `posix_spawn' 1419 /* Prefer the simpler `posix_spawn' if available. `posix_spawn'
1419 doesn't yet support setting up pseudoterminals, so we fall back 1420 doesn't yet support setting up pseudoterminals, so we fall back
1420 to `vfork' if we're supposed to use a pseudoterminal. */ 1421 to `vfork' if we're supposed to use a pseudoterminal. */
1421 1422
1422 bool use_posix_spawn = pty == NULL; 1423 bool use_posix_spawn = pty_name == NULL;
1423 1424
1424 posix_spawn_file_actions_t actions; 1425 posix_spawn_file_actions_t actions;
1425 posix_spawnattr_t attributes; 1426 posix_spawnattr_t attributes;
@@ -1473,7 +1474,9 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1473 /* vfork, and prevent local vars from being clobbered by the vfork. */ 1474 /* vfork, and prevent local vars from being clobbered by the vfork. */
1474 pid_t *volatile newpid_volatile = newpid; 1475 pid_t *volatile newpid_volatile = newpid;
1475 const char *volatile cwd_volatile = cwd; 1476 const char *volatile cwd_volatile = cwd;
1476 const char *volatile pty_volatile = pty; 1477 const char *volatile ptyname_volatile = pty_name;
1478 bool volatile ptyin_volatile = pty_in;
1479 bool volatile ptyout_volatile = pty_out;
1477 char **volatile argv_volatile = argv; 1480 char **volatile argv_volatile = argv;
1478 int volatile stdin_volatile = std_in; 1481 int volatile stdin_volatile = std_in;
1479 int volatile stdout_volatile = std_out; 1482 int volatile stdout_volatile = std_out;
@@ -1495,7 +1498,9 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1495 1498
1496 newpid = newpid_volatile; 1499 newpid = newpid_volatile;
1497 cwd = cwd_volatile; 1500 cwd = cwd_volatile;
1498 pty = pty_volatile; 1501 pty_name = ptyname_volatile;
1502 pty_in = ptyin_volatile;
1503 pty_out = ptyout_volatile;
1499 argv = argv_volatile; 1504 argv = argv_volatile;
1500 std_in = stdin_volatile; 1505 std_in = stdin_volatile;
1501 std_out = stdout_volatile; 1506 std_out = stdout_volatile;
@@ -1506,13 +1511,12 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1506 if (pid == 0) 1511 if (pid == 0)
1507#endif /* not WINDOWSNT */ 1512#endif /* not WINDOWSNT */
1508 { 1513 {
1509 bool pty_flag = pty != NULL;
1510 /* Make the pty be the controlling terminal of the process. */ 1514 /* Make the pty be the controlling terminal of the process. */
1511#ifdef HAVE_PTYS 1515#ifdef HAVE_PTYS
1512 dissociate_controlling_tty (); 1516 dissociate_controlling_tty ();
1513 1517
1514 /* Make the pty's terminal the controlling terminal. */ 1518 /* Make the pty's terminal the controlling terminal. */
1515 if (pty_flag && std_in >= 0) 1519 if (pty_in && std_in >= 0)
1516 { 1520 {
1517#ifdef TIOCSCTTY 1521#ifdef TIOCSCTTY
1518 /* We ignore the return value 1522 /* We ignore the return value
@@ -1521,7 +1525,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1521#endif 1525#endif
1522 } 1526 }
1523#if defined (LDISC1) 1527#if defined (LDISC1)
1524 if (pty_flag && std_in >= 0) 1528 if (pty_in && std_in >= 0)
1525 { 1529 {
1526 struct termios t; 1530 struct termios t;
1527 tcgetattr (std_in, &t); 1531 tcgetattr (std_in, &t);
@@ -1531,7 +1535,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1531 } 1535 }
1532#else 1536#else
1533#if defined (NTTYDISC) && defined (TIOCSETD) 1537#if defined (NTTYDISC) && defined (TIOCSETD)
1534 if (pty_flag && std_in >= 0) 1538 if (pty_in && std_in >= 0)
1535 { 1539 {
1536 /* Use new line discipline. */ 1540 /* Use new line discipline. */
1537 int ldisc = NTTYDISC; 1541 int ldisc = NTTYDISC;
@@ -1548,18 +1552,21 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1548 both TIOCSCTTY is defined. */ 1552 both TIOCSCTTY is defined. */
1549 /* Now close the pty (if we had it open) and reopen it. 1553 /* Now close the pty (if we had it open) and reopen it.
1550 This makes the pty the controlling terminal of the subprocess. */ 1554 This makes the pty the controlling terminal of the subprocess. */
1551 if (pty_flag) 1555 if (pty_name)
1552 { 1556 {
1553 1557
1554 /* I wonder if emacs_close (emacs_open (pty, ...)) 1558 /* I wonder if emacs_close (emacs_open (pty, ...))
1555 would work? */ 1559 would work? */
1556 if (std_in >= 0) 1560 if (pty_in && std_in >= 0)
1557 emacs_close (std_in); 1561 emacs_close (std_in);
1558 std_out = std_in = emacs_open_noquit (pty, O_RDWR, 0); 1562 int ptyfd = emacs_open_noquit (pty_name, O_RDWR, 0);
1559 1563 if (pty_in)
1564 std_in = ptyfd;
1565 if (pty_out)
1566 std_out = ptyfd;
1560 if (std_in < 0) 1567 if (std_in < 0)
1561 { 1568 {
1562 emacs_perror (pty); 1569 emacs_perror (pty_name);
1563 _exit (EXIT_CANCELED); 1570 _exit (EXIT_CANCELED);
1564 } 1571 }
1565 1572
@@ -1599,7 +1606,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
1599 /* Stop blocking SIGCHLD in the child. */ 1606 /* Stop blocking SIGCHLD in the child. */
1600 unblock_child_signal (oldset); 1607 unblock_child_signal (oldset);
1601 1608
1602 if (pty_flag) 1609 if (pty_out)
1603 child_setup_tty (std_out); 1610 child_setup_tty (std_out);
1604#endif 1611#endif
1605 1612
diff --git a/src/lisp.h b/src/lisp.h
index 8e36620fe53..fe6e98843d1 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4943,7 +4943,8 @@ extern void setup_process_coding_systems (Lisp_Object);
4943#endif 4943#endif
4944 4944
4945extern int emacs_spawn (pid_t *, int, int, int, char **, char **, 4945extern int emacs_spawn (pid_t *, int, int, int, char **, char **,
4946 const char *, const char *, const sigset_t *); 4946 const char *, const char *, bool, bool,
4947 const sigset_t *);
4947extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL; 4948extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL;
4948extern void init_callproc_1 (void); 4949extern void init_callproc_1 (void);
4949extern void init_callproc (void); 4950extern void init_callproc (void);
diff --git a/src/process.c b/src/process.c
index 1ac5a509e56..68dbd8b68bd 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1316,6 +1316,19 @@ set_process_filter_masks (struct Lisp_Process *p)
1316 add_process_read_fd (p->infd); 1316 add_process_read_fd (p->infd);
1317} 1317}
1318 1318
1319static bool
1320is_pty_from_symbol (Lisp_Object symbol)
1321{
1322 if (EQ (symbol, Qpty))
1323 return true;
1324 else if (EQ (symbol, Qpipe))
1325 return false;
1326 else if (NILP (symbol))
1327 return !NILP (Vprocess_connection_type);
1328 else
1329 report_file_error ("Unknown connection type", symbol);
1330}
1331
1319DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter, 1332DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter,
1320 2, 2, 0, 1333 2, 2, 0,
1321 doc: /* Give PROCESS the filter function FILTER; nil means default. 1334 doc: /* Give PROCESS the filter function FILTER; nil means default.
@@ -1741,15 +1754,18 @@ signals to stop and continue a process.
1741:connection-type TYPE -- TYPE is control type of device used to 1754:connection-type TYPE -- TYPE is control type of device used to
1742communicate with subprocesses. Values are `pipe' to use a pipe, `pty' 1755communicate with subprocesses. Values are `pipe' to use a pipe, `pty'
1743to use a pty, or nil to use the default specified through 1756to use a pty, or nil to use the default specified through
1744`process-connection-type'. 1757`process-connection-type'. If TYPE is a cons (INPUT . OUTPUT), then
1758INPUT will be used for standard input and OUTPUT for standard output
1759(and standard error if `:stderr' is nil).
1745 1760
1746:filter FILTER -- Install FILTER as the process filter. 1761:filter FILTER -- Install FILTER as the process filter.
1747 1762
1748:sentinel SENTINEL -- Install SENTINEL as the process sentinel. 1763:sentinel SENTINEL -- Install SENTINEL as the process sentinel.
1749 1764
1750:stderr STDERR -- STDERR is either a buffer or a pipe process attached 1765:stderr STDERR -- STDERR is either a buffer or a pipe process attached
1751to the standard error of subprocess. Specifying this implies 1766to the standard error of subprocess. When specifying this, the
1752`:connection-type' is set to `pipe'. If STDERR is nil, standard error 1767subprocess's standard error will always communicate via a pipe, no
1768matter the value of `:connection-type'. If STDERR is nil, standard error
1753is mixed with standard output and sent to BUFFER or FILTER. (Note 1769is mixed with standard output and sent to BUFFER or FILTER. (Note
1754that specifying :stderr will create a new, separate (but associated) 1770that specifying :stderr will create a new, separate (but associated)
1755process, with its own filter and sentinel. See 1771process, with its own filter and sentinel. See
@@ -1845,22 +1861,20 @@ usage: (make-process &rest ARGS) */)
1845 CHECK_TYPE (NILP (tem), Qnull, tem); 1861 CHECK_TYPE (NILP (tem), Qnull, tem);
1846 1862
1847 tem = plist_get (contact, QCconnection_type); 1863 tem = plist_get (contact, QCconnection_type);
1848 if (EQ (tem, Qpty)) 1864 if (CONSP (tem))
1849 XPROCESS (proc)->pty_flag = true; 1865 {
1850 else if (EQ (tem, Qpipe)) 1866 XPROCESS (proc)->pty_in = is_pty_from_symbol (XCAR (tem));
1851 XPROCESS (proc)->pty_flag = false; 1867 XPROCESS (proc)->pty_out = is_pty_from_symbol (XCDR (tem));
1852 else if (NILP (tem)) 1868 }
1853 XPROCESS (proc)->pty_flag = !NILP (Vprocess_connection_type);
1854 else 1869 else
1855 report_file_error ("Unknown connection type", tem);
1856
1857 if (!NILP (stderrproc))
1858 { 1870 {
1859 pset_stderrproc (XPROCESS (proc), stderrproc); 1871 XPROCESS (proc)->pty_in = XPROCESS (proc)->pty_out =
1860 1872 is_pty_from_symbol (tem);
1861 XPROCESS (proc)->pty_flag = false;
1862 } 1873 }
1863 1874
1875 if (!NILP (stderrproc))
1876 pset_stderrproc (XPROCESS (proc), stderrproc);
1877
1864#ifdef HAVE_GNUTLS 1878#ifdef HAVE_GNUTLS
1865 /* AKA GNUTLS_INITSTAGE(proc). */ 1879 /* AKA GNUTLS_INITSTAGE(proc). */
1866 verify (GNUTLS_STAGE_EMPTY == 0); 1880 verify (GNUTLS_STAGE_EMPTY == 0);
@@ -2099,66 +2113,80 @@ static void
2099create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) 2113create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
2100{ 2114{
2101 struct Lisp_Process *p = XPROCESS (process); 2115 struct Lisp_Process *p = XPROCESS (process);
2102 int inchannel, outchannel; 2116 int inchannel = -1, outchannel = -1;
2103 pid_t pid = -1; 2117 pid_t pid = -1;
2104 int vfork_errno; 2118 int vfork_errno;
2105 int forkin, forkout, forkerr = -1; 2119 int forkin, forkout, forkerr = -1;
2106 bool pty_flag = 0; 2120 bool pty_in = false, pty_out = false;
2107 char pty_name[PTY_NAME_SIZE]; 2121 char pty_name[PTY_NAME_SIZE];
2108 Lisp_Object lisp_pty_name = Qnil; 2122 Lisp_Object lisp_pty_name = Qnil;
2123 int ptychannel = -1, pty_tty = -1;
2109 sigset_t oldset; 2124 sigset_t oldset;
2110 2125
2111 /* Ensure that the SIGCHLD handler can notify 2126 /* Ensure that the SIGCHLD handler can notify
2112 `wait_reading_process_output'. */ 2127 `wait_reading_process_output'. */
2113 child_signal_init (); 2128 child_signal_init ();
2114 2129
2115 inchannel = outchannel = -1; 2130 if (p->pty_in || p->pty_out)
2116 2131 ptychannel = allocate_pty (pty_name);
2117 if (p->pty_flag)
2118 outchannel = inchannel = allocate_pty (pty_name);
2119 2132
2120 if (inchannel >= 0) 2133 if (ptychannel >= 0)
2121 { 2134 {
2122 p->open_fd[READ_FROM_SUBPROCESS] = inchannel;
2123#if ! defined (USG) || defined (USG_SUBTTY_WORKS) 2135#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
2124 /* On most USG systems it does not work to open the pty's tty here, 2136 /* On most USG systems it does not work to open the pty's tty here,
2125 then close it and reopen it in the child. */ 2137 then close it and reopen it in the child. */
2126 /* Don't let this terminal become our controlling terminal 2138 /* Don't let this terminal become our controlling terminal
2127 (in case we don't have one). */ 2139 (in case we don't have one). */
2128 forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); 2140 pty_tty = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
2129 if (forkin < 0) 2141 if (pty_tty < 0)
2130 report_file_error ("Opening pty", Qnil); 2142 report_file_error ("Opening pty", Qnil);
2131 p->open_fd[SUBPROCESS_STDIN] = forkin;
2132#else
2133 forkin = forkout = -1;
2134#endif /* not USG, or USG_SUBTTY_WORKS */ 2143#endif /* not USG, or USG_SUBTTY_WORKS */
2135 pty_flag = 1; 2144 pty_in = p->pty_in;
2145 pty_out = p->pty_out;
2136 lisp_pty_name = build_string (pty_name); 2146 lisp_pty_name = build_string (pty_name);
2137 } 2147 }
2148
2149 /* Set up stdin for the child process. */
2150 if (ptychannel >= 0 && p->pty_in)
2151 {
2152 p->open_fd[SUBPROCESS_STDIN] = forkin = pty_tty;
2153 outchannel = ptychannel;
2154 }
2138 else 2155 else
2139 { 2156 {
2140 if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0 2157 if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0)
2141 || emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0)
2142 report_file_error ("Creating pipe", Qnil); 2158 report_file_error ("Creating pipe", Qnil);
2143 forkin = p->open_fd[SUBPROCESS_STDIN]; 2159 forkin = p->open_fd[SUBPROCESS_STDIN];
2144 outchannel = p->open_fd[WRITE_TO_SUBPROCESS]; 2160 outchannel = p->open_fd[WRITE_TO_SUBPROCESS];
2161 }
2162
2163 /* Set up stdout for the child process. */
2164 if (ptychannel >= 0 && p->pty_out)
2165 {
2166 forkout = pty_tty;
2167 p->open_fd[READ_FROM_SUBPROCESS] = inchannel = ptychannel;
2168 }
2169 else
2170 {
2171 if (emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0)
2172 report_file_error ("Creating pipe", Qnil);
2145 inchannel = p->open_fd[READ_FROM_SUBPROCESS]; 2173 inchannel = p->open_fd[READ_FROM_SUBPROCESS];
2146 forkout = p->open_fd[SUBPROCESS_STDOUT]; 2174 forkout = p->open_fd[SUBPROCESS_STDOUT];
2147 2175
2148#if defined(GNU_LINUX) && defined(F_SETPIPE_SZ) 2176#if defined(GNU_LINUX) && defined(F_SETPIPE_SZ)
2149 fcntl (inchannel, F_SETPIPE_SZ, read_process_output_max); 2177 fcntl (inchannel, F_SETPIPE_SZ, read_process_output_max);
2150#endif 2178#endif
2179 }
2151 2180
2152 if (!NILP (p->stderrproc)) 2181 if (!NILP (p->stderrproc))
2153 { 2182 {
2154 struct Lisp_Process *pp = XPROCESS (p->stderrproc); 2183 struct Lisp_Process *pp = XPROCESS (p->stderrproc);
2155 2184
2156 forkerr = pp->open_fd[SUBPROCESS_STDOUT]; 2185 forkerr = pp->open_fd[SUBPROCESS_STDOUT];
2157 2186
2158 /* Close unnecessary file descriptors. */ 2187 /* Close unnecessary file descriptors. */
2159 close_process_fd (&pp->open_fd[WRITE_TO_SUBPROCESS]); 2188 close_process_fd (&pp->open_fd[WRITE_TO_SUBPROCESS]);
2160 close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]); 2189 close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]);
2161 }
2162 } 2190 }
2163 2191
2164 if (FD_SETSIZE <= inchannel || FD_SETSIZE <= outchannel) 2192 if (FD_SETSIZE <= inchannel || FD_SETSIZE <= outchannel)
@@ -2183,7 +2211,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
2183 we just reopen the device (see emacs_get_tty_pgrp) as this is 2211 we just reopen the device (see emacs_get_tty_pgrp) as this is
2184 more portable (see USG_SUBTTY_WORKS above). */ 2212 more portable (see USG_SUBTTY_WORKS above). */
2185 2213
2186 p->pty_flag = pty_flag; 2214 p->pty_in = pty_in;
2215 p->pty_out = pty_out;
2187 pset_status (p, Qrun); 2216 pset_status (p, Qrun);
2188 2217
2189 if (!EQ (p->command, Qt) 2218 if (!EQ (p->command, Qt)
@@ -2199,13 +2228,15 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
2199 block_input (); 2228 block_input ();
2200 block_child_signal (&oldset); 2229 block_child_signal (&oldset);
2201 2230
2202 pty_flag = p->pty_flag; 2231 pty_in = p->pty_in;
2203 eassert (pty_flag == ! NILP (lisp_pty_name)); 2232 pty_out = p->pty_out;
2233 eassert ((pty_in || pty_out) == ! NILP (lisp_pty_name));
2204 2234
2205 vfork_errno 2235 vfork_errno
2206 = emacs_spawn (&pid, forkin, forkout, forkerr, new_argv, env, 2236 = emacs_spawn (&pid, forkin, forkout, forkerr, new_argv, env,
2207 SSDATA (current_dir), 2237 SSDATA (current_dir),
2208 pty_flag ? SSDATA (lisp_pty_name) : NULL, &oldset); 2238 pty_in || pty_out ? SSDATA (lisp_pty_name) : NULL,
2239 pty_in, pty_out, &oldset);
2209 2240
2210 eassert ((vfork_errno == 0) == (0 < pid)); 2241 eassert ((vfork_errno == 0) == (0 < pid));
2211 2242
@@ -2263,7 +2294,7 @@ create_pty (Lisp_Object process)
2263{ 2294{
2264 struct Lisp_Process *p = XPROCESS (process); 2295 struct Lisp_Process *p = XPROCESS (process);
2265 char pty_name[PTY_NAME_SIZE]; 2296 char pty_name[PTY_NAME_SIZE];
2266 int pty_fd = !p->pty_flag ? -1 : allocate_pty (pty_name); 2297 int pty_fd = !(p->pty_in || p->pty_out) ? -1 : allocate_pty (pty_name);
2267 2298
2268 if (pty_fd >= 0) 2299 if (pty_fd >= 0)
2269 { 2300 {
@@ -2301,7 +2332,7 @@ create_pty (Lisp_Object process)
2301 we just reopen the device (see emacs_get_tty_pgrp) as this is 2332 we just reopen the device (see emacs_get_tty_pgrp) as this is
2302 more portable (see USG_SUBTTY_WORKS above). */ 2333 more portable (see USG_SUBTTY_WORKS above). */
2303 2334
2304 p->pty_flag = 1; 2335 p->pty_in = p->pty_out = true;
2305 pset_status (p, Qrun); 2336 pset_status (p, Qrun);
2306 setup_process_coding_systems (process); 2337 setup_process_coding_systems (process);
2307 2338
@@ -2412,7 +2443,7 @@ usage: (make-pipe-process &rest ARGS) */)
2412 p->kill_without_query = 1; 2443 p->kill_without_query = 1;
2413 if (tem = plist_get (contact, QCstop), !NILP (tem)) 2444 if (tem = plist_get (contact, QCstop), !NILP (tem))
2414 pset_command (p, Qt); 2445 pset_command (p, Qt);
2415 eassert (! p->pty_flag); 2446 eassert (! p->pty_in && ! p->pty_out);
2416 2447
2417 if (!EQ (p->command, Qt) 2448 if (!EQ (p->command, Qt)
2418 && !EQ (p->filter, Qt)) 2449 && !EQ (p->filter, Qt))
@@ -3147,7 +3178,7 @@ usage: (make-serial-process &rest ARGS) */)
3147 p->kill_without_query = 1; 3178 p->kill_without_query = 1;
3148 if (tem = plist_get (contact, QCstop), !NILP (tem)) 3179 if (tem = plist_get (contact, QCstop), !NILP (tem))
3149 pset_command (p, Qt); 3180 pset_command (p, Qt);
3150 eassert (! p->pty_flag); 3181 eassert (! p->pty_in && ! p->pty_out);
3151 3182
3152 if (!EQ (p->command, Qt) 3183 if (!EQ (p->command, Qt)
3153 && !EQ (p->filter, Qt)) 3184 && !EQ (p->filter, Qt))
@@ -6808,7 +6839,7 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
6808 error ("Process %s is not active", 6839 error ("Process %s is not active",
6809 SDATA (p->name)); 6840 SDATA (p->name));
6810 6841
6811 if (!p->pty_flag) 6842 if (! p->pty_in)
6812 current_group = Qnil; 6843 current_group = Qnil;
6813 6844
6814 /* If we are using pgrps, get a pgrp number and make it negative. */ 6845 /* If we are using pgrps, get a pgrp number and make it negative. */
@@ -7177,7 +7208,7 @@ process has been transmitted to the serial port. */)
7177 send_process (proc, "", 0, Qnil); 7208 send_process (proc, "", 0, Qnil);
7178 } 7209 }
7179 7210
7180 if (XPROCESS (proc)->pty_flag) 7211 if (XPROCESS (proc)->pty_in)
7181 send_process (proc, "\004", 1, Qnil); 7212 send_process (proc, "\004", 1, Qnil);
7182 else if (EQ (XPROCESS (proc)->type, Qserial)) 7213 else if (EQ (XPROCESS (proc)->type, Qserial))
7183 { 7214 {
diff --git a/src/process.h b/src/process.h
index 392b661ce69..92baf0c4cb9 100644
--- a/src/process.h
+++ b/src/process.h
@@ -156,8 +156,9 @@ struct Lisp_Process
156 /* True means kill silently if Emacs is exited. 156 /* True means kill silently if Emacs is exited.
157 This is the inverse of the `query-on-exit' flag. */ 157 This is the inverse of the `query-on-exit' flag. */
158 bool_bf kill_without_query : 1; 158 bool_bf kill_without_query : 1;
159 /* True if communicating through a pty. */ 159 /* True if communicating through a pty for input or output. */
160 bool_bf pty_flag : 1; 160 bool_bf pty_in : 1;
161 bool_bf pty_out : 1;
161 /* Flag to set coding-system of the process buffer from the 162 /* Flag to set coding-system of the process buffer from the
162 coding_system used to decode process output. */ 163 coding_system used to decode process output. */
163 bool_bf inherit_coding_system_flag : 1; 164 bool_bf inherit_coding_system_flag : 1;