1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-12 01:42:37 -07:00

Don’t stuff keyboard input uselessly

Also, document stuffing better.
* src/keyboard.c (stuff_buffered_input):
Give up on stuffing if it fails.
* src/sysdep.c (stuff_char): Return failure indication.
This commit is contained in:
Paul Eggert 2026-02-28 09:03:27 -08:00
parent 936472345d
commit aed1c8b536
6 changed files with 42 additions and 49 deletions

View file

@ -504,6 +504,8 @@ THINGS TO DO
** flow-ctrl.el must be updated.
** Fix stuff_char for multi-tty. Doesn't seem to be of high priority.
For security reasons stuff_char does not work by default on many
platforms, which makes such a fix even lower priority.
DIARY OF CHANGES
----------------

View file

@ -711,12 +711,11 @@ If @var{exit-data} is an integer, that is used as the exit status of
the Emacs process. (This is useful primarily in batch operation; see
@ref{Batch Mode}.)
If @var{exit-data} is a string, its contents are stuffed into the
terminal input buffer so that the shell (or whatever program next reads
input) can read them. This is only possible on some systems. Note that
recent versions of GNU/Linux disable the system API required for
stuffing the string into the terminal input, so this might not work on
your system without special privileges.
If @var{exit-data} is a string, its contents (followed by a newline) are
stuffed into the terminal input buffer so that the shell (or whatever
program next reads input) can read them. However, stuffing is silently
skipped if Emacs is not running interactively on a terminal, or if
stuffing requires special privileges or is not supported on this platform.
If @var{exit-data} is neither an integer nor a string, or is omitted,
that means to use the (system-specific) exit status which indicates
@ -816,6 +815,9 @@ before suspending Emacs, or this function signals an error.
If @var{string} is non-@code{nil}, its characters are sent to Emacs's
superior shell, to be read as terminal input.
However, this action is skipped if Emacs is not running interactively on
a terminal, or if stuffing characters into the terminal input requires
special privileges or is not supported on this platform.
Before suspending, @code{suspend-emacs} runs the normal hook
@code{suspend-hook}. After the user resumes Emacs,
@ -840,7 +842,7 @@ Here is an example of how you could use these hooks:
@c The sit-for prevents the @code{nil} that suspend-emacs returns
@c hiding the message.
Here is what you would see upon evaluating @code{(suspend-emacs "pwd")}:
Here is what you would see upon evaluating @code{(suspend-emacs)}:
@smallexample
@group
@ -851,8 +853,6 @@ Really suspend? @kbd{y}
@group
---------- Parent Shell ----------
bash$ pwd
/home/username
bash$ fg
@end group

View file

@ -2947,9 +2947,9 @@ sort_args (int argc, char **argv)
DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 2, "P",
doc: /* Exit the Emacs job and kill it.
If ARG is an integer, return ARG as the exit program code.
If ARG is a string, stuff it as keyboard input. (This might
not work on modern systems due to security considerations, or
not at all.)
If ARG is a string, stuff it and then a newline as keyboard input,
if Emacs is running interactively on a terminal and the platform
supports and allows stuffing; this may need special privileges.
Any other value of ARG, or ARG omitted, means return an
exit code that indicates successful program termination.

View file

@ -12421,19 +12421,15 @@ DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
If `cannot-suspend' is non-nil, or if the system doesn't support job
control, run a subshell instead.
If optional arg STUFFSTRING is non-nil, its characters are stuffed
to be read as terminal input by Emacs's parent, after suspension.
If optional arg STUFFSTRING is non-nil, stuff it and then a newline as
keyboard input, if Emacs is running interactively on a terminal and the
platform supports and allows stuffing; this may need special privileges.
Before suspending, run the normal hook `suspend-hook'.
After resumption run the normal hook `suspend-resume-hook'.
Some operating systems cannot stop the Emacs process and resume it later.
On such systems, Emacs starts a subshell instead of suspending.
On some operating systems, stuffing characters into terminal input
buffer requires special privileges or is not supported at all.
On such systems, calling this function with non-nil STUFFSTRING might
either signal an error or silently fail to stuff the characters. */)
On such systems, Emacs starts a subshell instead of suspending. */)
(Lisp_Object stuffstring)
{
specpdl_ref count = SPECPDL_INDEX ();
@ -12472,38 +12468,34 @@ either signal an error or silently fail to stuff the characters. */)
return Qnil;
}
/* If STUFFSTRING is a string, stuff its contents as pending terminal input.
Then in any case stuff anything Emacs has read ahead and not used. */
/* If STUFFSTRING is a string, stuff its contents and then a newline as
pending terminal input. Then stuff anything Emacs has read ahead and
not used. However, do nothing if stuffing does not work. */
void
stuff_buffered_input (Lisp_Object stuffstring)
{
#ifdef SIGTSTP /* stuff_char is defined if SIGTSTP. */
register unsigned char *p;
int bad_stuff = 0;
if (STRINGP (stuffstring))
{
register ptrdiff_t count;
p = SDATA (stuffstring);
count = SBYTES (stuffstring);
while (count-- > 0)
stuff_char (*p++);
stuff_char ('\n');
char *p = SSDATA (stuffstring);
for (ptrdiff_t i = SBYTES (stuffstring); !bad_stuff && 0 < i; i--)
bad_stuff = stuff_char (*p++);
if (!bad_stuff)
bad_stuff = stuff_char ('\n');
}
/* Anything we have read ahead, put back for the shell to read. */
/* ?? What should this do when we have multiple keyboards??
Should we ignore anything that was typed in at the "wrong" kboard?
rms: we should stuff everything back into the kboard
it came from. */
/* Anything we have read ahead, put back for the shell to read.
When we have multiple keyboards, we should stuff everything back
into the keyboard it came from, but fixing this is low priority as
many systems prohibit stuffing for security reasons. */
for (; kbd_fetch_ptr != kbd_store_ptr;
kbd_fetch_ptr = next_kbd_event (kbd_fetch_ptr))
{
if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT)
stuff_char (kbd_fetch_ptr->ie.code);
if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT && !bad_stuff)
bad_stuff = stuff_char (kbd_fetch_ptr->ie.code);
clear_event (&kbd_fetch_ptr->ie);
}

View file

@ -5280,7 +5280,7 @@ maybe_disable_address_randomization (int argc, char **argv)
extern int emacs_exec_file (char const *, char *const *, char *const *);
extern void init_standard_fds (void);
extern char *emacs_get_current_dir_name (void);
extern void stuff_char (char c);
extern int stuff_char (char c);
extern void init_foreground_group (void);
extern void sys_subshell (void);
extern void sys_suspend (void);

View file

@ -390,23 +390,22 @@ discard_tty_input (void)
/* Arrange for character C to be read as the next input from
the terminal.
Return 0 on success, -1 otherwise.
XXX What if we have multiple ttys?
*/
void
int
stuff_char (char c)
{
if (! (FRAMEP (selected_frame)
&& FRAME_LIVE_P (XFRAME (selected_frame))
&& FRAME_TERMCAP_P (XFRAME (selected_frame))))
return;
/* Should perhaps error if in batch mode */
#ifdef TIOCSTI
ioctl (fileno (CURTTY()->input), TIOCSTI, &c);
#else /* no TIOCSTI */
error ("Cannot stuff terminal input characters in this version of Unix");
if (FRAMEP (selected_frame)
&& FRAME_LIVE_P (XFRAME (selected_frame))
&& FRAME_TERMCAP_P (XFRAME (selected_frame)))
return ioctl (fileno (CURTTY()->input), TIOCSTI, &c);
#endif /* no TIOCSTI */
return -1;
}
#endif /* SIGTSTP */