diff options
| author | Jim Porter | 2022-07-17 20:25:00 -0700 |
|---|---|---|
| committer | Jim Porter | 2022-08-05 17:58:54 -0700 |
| commit | d7b89ea4077d4fe677ba0577245328819ee79cdc (patch) | |
| tree | d4e499042bdf2f301be7f2d7ec05f0d1bfd8d44b /src | |
| parent | b70369c557efed3dcd86dc64a2e73e3480dea6af (diff) | |
| download | emacs-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.c | 37 | ||||
| -rw-r--r-- | src/lisp.h | 3 | ||||
| -rw-r--r-- | src/process.c | 129 | ||||
| -rw-r--r-- | src/process.h | 5 |
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, | |||
| 1412 | int | 1412 | int |
| 1413 | emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | 1413 | emacs_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 | ||
| 4945 | extern int emacs_spawn (pid_t *, int, int, int, char **, char **, | 4945 | extern 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 *); | ||
| 4947 | extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL; | 4948 | extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL; |
| 4948 | extern void init_callproc_1 (void); | 4949 | extern void init_callproc_1 (void); |
| 4949 | extern void init_callproc (void); | 4950 | extern 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 | ||
| 1319 | static bool | ||
| 1320 | is_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 | |||
| 1319 | DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter, | 1332 | DEFUN ("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 |
| 1742 | communicate with subprocesses. Values are `pipe' to use a pipe, `pty' | 1755 | communicate with subprocesses. Values are `pipe' to use a pipe, `pty' |
| 1743 | to use a pty, or nil to use the default specified through | 1756 | to 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 |
| 1758 | INPUT 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 |
| 1751 | to the standard error of subprocess. Specifying this implies | 1766 | to the standard error of subprocess. When specifying this, the |
| 1752 | `:connection-type' is set to `pipe'. If STDERR is nil, standard error | 1767 | subprocess's standard error will always communicate via a pipe, no |
| 1768 | matter the value of `:connection-type'. If STDERR is nil, standard error | ||
| 1753 | is mixed with standard output and sent to BUFFER or FILTER. (Note | 1769 | is mixed with standard output and sent to BUFFER or FILTER. (Note |
| 1754 | that specifying :stderr will create a new, separate (but associated) | 1770 | that specifying :stderr will create a new, separate (but associated) |
| 1755 | process, with its own filter and sentinel. See | 1771 | process, 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 | |||
| 2099 | create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | 2113 | create_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; |