aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.c
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/process.c
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/process.c')
-rw-r--r--src/process.c129
1 files changed, 80 insertions, 49 deletions
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 {