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/callproc.c | |
| 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/callproc.c')
| -rw-r--r-- | src/callproc.c | 37 |
1 files changed, 22 insertions, 15 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 | ||