1 /* ttyio.c - tty i/O functions
2 * Copyright (C) 1997-2019 Werner Koch
3 * Copyright (C) 1998-2020 Free Software Foundation, Inc.
4 * Copyright (C) 2015-2020 g10 Code GmbH
6 * This file is part of GnuPG.
8 * This file is free software; you can redistribute it and/or modify
9 * it under the terms of either
11 * - the GNU Lesser General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at
13 * your option) any later version.
17 * - the GNU General Public License as published by the Free
18 * Software Foundation; either version 2 of the License, or (at
19 * your option) any later version.
21 * or both in parallel, as here.
23 * This file is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, see <https://www.gnu.org/licenses/>.
30 * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
44 /* simulate termios with termio */
46 # define termios termio
47 # define tcsetattr ioctl
48 # define TCSAFLUSH TCSETAF
49 # define tcgetattr(A,B) ioctl(A,TCGETA,B)
50 # define HAVE_TCGETATTR
53 #ifdef HAVE_W32_SYSTEM
54 # ifdef HAVE_WINSOCK2_H
55 # include <winsock2.h>
58 # ifdef HAVE_TCGETATTR
59 # error mingw32 and termios
68 #include "common-defs.h"
70 #define CONTROL_D ('D' - 'A' + 1)
73 #ifdef HAVE_W32_SYSTEM
77 #define DEF_INPMODE (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT \
78 |ENABLE_PROCESSED_INPUT )
79 #define HID_INPMODE (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT )
80 #define DEF_OUTMODE (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)
83 static FILE *ttyfp = NULL;
86 static int initialized;
87 static int last_prompt_len;
89 static int no_terminal;
92 static struct termios termsave;
93 static int restore_termios;
96 /* Hooks set by gpgrlhelp.c if required. */
97 static void (*my_rl_set_completer) (rl_completion_func_t *);
98 static void (*my_rl_inhibit_completion) (int);
99 static void (*my_rl_cleanup_after_signal) (void);
100 static void (*my_rl_init_stream) (FILE *);
101 static char *(*my_rl_readline) (const char*);
102 static void (*my_rl_add_history) (const char*);
103 static int (*my_rl_rw_history)(const char *, int, int);
105 /* This is a wrapper around ttyname so that we can use it even when
106 the standard streams are redirected. It figures the name out the
107 first time and returns it in a statically allocated buffer. */
109 tty_get_ttyname (void)
113 /* On a GNU system ctermid() always return /dev/tty, so this does
114 not make much sense - however if it is ever changed we do the
122 /* Note that despite our checks for these macros the function is
123 not necessarily thread save. We mainly do this for
124 portability reasons, in case L_ctermid is not defined. */
125 # if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_POSIX_TRHEADS)
126 char buffer[L_ctermid];
127 s = ctermid (buffer);
135 #endif /*HAVE_CTERMID*/
136 /* Assume the standard tty on memory error or when there is no
138 return name? name : "/dev/tty";
143 #ifdef HAVE_TCGETATTR
149 restore_termios = 0; /* do it prior in case it is interrupted again */
150 if (tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave))
151 log_error ("tcsetattr() failed: %s\n", strerror (errno));
154 #endif /*HAVE_TCGETATTR*/
163 #ifdef HAVE_W32_SYSTEM
165 SECURITY_ATTRIBUTES sa;
167 memset (&sa, 0, sizeof(sa));
168 sa.nLength = sizeof(sa);
169 sa.bInheritHandle = TRUE;
170 con.out = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
171 FILE_SHARE_READ|FILE_SHARE_WRITE,
172 &sa, OPEN_EXISTING, 0, 0 );
173 if (con.out == INVALID_HANDLE_VALUE)
174 log_fatal ("open(CONOUT$) failed: %s\n", w32_strerror (-1));
176 memset (&sa, 0, sizeof(sa));
177 sa.nLength = sizeof(sa);
178 sa.bInheritHandle = TRUE;
179 con.in = CreateFileA ("CONIN$", GENERIC_READ|GENERIC_WRITE,
180 FILE_SHARE_READ|FILE_SHARE_WRITE,
181 &sa, OPEN_EXISTING, 0, 0 );
182 if (con.in == INVALID_HANDLE_VALUE)
183 log_fatal ("open(CONIN$) failed: %s\n", w32_strerror (-1));
185 SetConsoleMode (con.in, DEF_INPMODE);
186 SetConsoleMode (con.out, DEF_OUTMODE);
189 ttyfp = batchmode? stderr : fopen (tty_get_ttyname (), "r+");
192 log_error ("cannot open '%s': %s\n", tty_get_ttyname (), strerror(errno));
195 if (my_rl_init_stream)
196 my_rl_init_stream (ttyfp);
199 #ifdef HAVE_TCGETATTR
208 tty_batchmode( int onoff )
217 tty_no_terminal(int onoff)
219 int old = no_terminal;
220 no_terminal = onoff ? 1 : 0;
225 #ifdef HAVE_W32_SYSTEM
226 /* Write the UTF-8 encoded STRING to the console. */
228 w32_write_console (const char *string)
233 wstring = utf8_to_wchar (string);
235 log_fatal ("w32_write_console failed: %s", strerror (errno));
236 n = wcslen (wstring);
238 if (!WriteConsoleW (con.out, wstring, n, &nwritten, NULL))
244 log_info ("WriteConsole failed: %s", w32_strerror (-1));
245 log_info ("Please configure a suitable font for the console\n");
248 if (!WriteConsoleA (con.out, string, n , &nwritten, NULL))
249 log_fatal ("WriteConsole fallback failed: %s", w32_strerror (-1));
254 log_fatal ("WriteConsole failed: %lu != %lu\n",
255 (unsigned long)n, (unsigned long)nwritten);
257 last_prompt_len += n;
260 #endif /*HAVE_W32_SYSTEM*/
264 tty_printf (const char *fmt, ... )
274 va_start (arg_ptr, fmt);
276 #ifdef HAVE_W32_SYSTEM
280 vasprintf(&buf, fmt, arg_ptr);
282 log_bug ("vasprintf() failed\n");
283 w32_write_console (buf);
287 last_prompt_len += vfprintf (ttyfp, fmt, arg_ptr) ;
294 /* Same as tty_printf but if FP is not NULL, behave like a regular
297 tty_fprintf (estream_t fp, const char *fmt, ... )
303 va_start (arg_ptr, fmt) ;
304 es_vfprintf (fp, fmt, arg_ptr );
315 va_start (arg_ptr, fmt);
317 #ifdef HAVE_W32_SYSTEM
321 vasprintf (&buf, fmt, arg_ptr);
323 log_bug ("vasprintf() failed\n");
324 w32_write_console (buf);
328 last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
336 /* Print a string, but filter all control characters out. If FP is
337 * not NULL print to that stream instead to the tty. */
339 do_print_string (estream_t fp, const byte *p, size_t n )
341 if (no_terminal && !fp)
344 if (!initialized && !fp)
349 print_utf8_buffer (fp, p, n);
353 #ifdef HAVE_W32_SYSTEM
354 /* Not so effective, change it if you want */
364 tty_printf ("\\x%02x", *p);
367 tty_printf ("%c", *p);
380 fprintf (ttyfp, "x%02x", *p );
390 tty_print_utf8_string2 (estream_t fp, const byte *p, size_t n, size_t max_n)
395 if (no_terminal && !fp)
398 /* We can handle plain ascii simpler, so check for it first. */
399 for(i=0; i < n; i++ )
406 buf = utf8_to_native ((const char *)p, n, 0);
407 if (max_n && (strlen (buf) > max_n))
409 /* (utf8_to_native already did the control character quoting) */
410 tty_fprintf (fp, "%s", buf);
415 if (max_n && (n > max_n))
417 do_print_string (fp, p, n );
423 tty_print_utf8_string (const byte *p, size_t n)
425 tty_print_utf8_string2 (NULL, p, n, 0);
429 /* Read a string from the tty using PROMPT. If HIDDEN is set the
430 * input is not echoed. */
432 do_get (const char *prompt, int hidden)
435 int n; /* Allocated size of BUF. */
436 int i; /* Number of bytes in BUF. */
438 #ifdef HAVE_W32_SYSTEM
447 log_error (_("Sorry, we are in batchmode - can't get input\n"));
453 log_error (_("Sorry, no terminal at all requested - can't get input\n"));
461 tty_printf ("%s", prompt);
462 buf = xmalloc ((n=50));
465 #ifdef HAVE_W32_SYSTEM
467 SetConsoleMode(con.in, HID_INPMODE );
474 const unsigned char *s;
476 if (!ReadConsoleW (con.in, wbuf, 1, &nread, NULL))
477 log_fatal ("ReadConsole failed: %s", w32_strerror (-1));
483 utf8buf = wchar_to_utf8 (wbuf);
486 log_info ("wchar_to_utf8 failed: %s\n", strerror (errno));
488 log_fatal (_("too many errors; giving up\n"));
491 if (*utf8buf == '\n')
495 log_info ("ReadConsole returned more than requested"
496 " (0x0a,0x%02x)\n", utf8buf[1]);
498 log_fatal (_("too many errors; giving up\n"));
505 for (s=utf8buf; *s; s++)
509 c = ' '; /* Map tab to a space. */
510 else if ((c >= 0 && c <= 0x1f) || c == 0x7f)
511 continue; /* Remove control characters. */
515 buf = xrealloc (buf, n);
523 SetConsoleMode(con.in, DEF_INPMODE );
529 #ifdef HAVE_TCGETATTR
532 if (tcgetattr(fileno(ttyfp), &termsave))
533 log_fatal ("tcgetattr() failed: %s\n", strerror(errno));
536 term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
537 if (tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
538 log_fatal("tcsetattr() failed: %s\n", strerror(errno));
539 #endif /*HAVE_TCGETATTR*/
542 /* fixme: How can we avoid that the \n is echoed w/o disabling
543 * canonical mode - w/o this kill_prompt can't work */
544 while (read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n')
550 log_info (_("Control-D detected\n"));
552 if (c == '\t') /* Map tab to a space. */
554 else if ( (c >= 0 && c <= 0x1f) || c == 0x7f)
555 continue; /* Skip all other ASCII control characters. */
559 buf = xrealloc (buf, n);
571 #ifdef HAVE_TCGETATTR
572 if (tcsetattr (fileno(ttyfp), TCSAFLUSH, &termsave))
573 log_error ("tcsetattr() failed: %s\n", strerror(errno));
575 #endif /*HAVE_TCGETATTR*/
585 /* Note: This function never returns NULL. */
587 tty_get( const char *prompt )
589 if (!batchmode && !no_terminal && my_rl_readline && my_rl_add_history)
599 line = my_rl_readline (prompt?prompt:"");
601 /* We need to copy it to memory controlled by our malloc
602 implementations; further we need to convert an EOF to our
604 buf = xmalloc(line? strlen(line)+1:2);
609 if (strlen (buf) > 2 )
610 my_rl_add_history (line); /* Note that we test BUF but add LINE. */
621 return do_get ( prompt, 0 );
625 /* Variable argument version of tty_get. The prompt is actually a
626 * format string with arguments. */
628 tty_getf (const char *promptfmt, ... )
634 va_start (arg_ptr, promptfmt);
635 if (gpgrt_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
636 log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
638 answer = tty_get (prompt);
645 tty_get_hidden( const char *prompt )
647 return do_get (prompt, 1);
652 tty_kill_prompt (void)
662 if (!last_prompt_len)
664 #ifdef HAVE_W32_SYSTEM
665 tty_printf ("\r%*s\r", last_prompt_len, "");
670 for (i=0; i < last_prompt_len; i ++ )
681 tty_get_answer_is_yes( const char *prompt )
686 p = tty_get (prompt);
688 yes = answer_is_yes (p);
695 /* Called by gnupg_rl_initialize to setup the readline support. */
697 tty_private_set_rl_hooks (void (*init_stream) (FILE *),
698 void (*set_completer) (rl_completion_func_t*),
699 void (*inhibit_completion) (int),
700 void (*cleanup_after_signal) (void),
701 char *(*readline_fun) (const char*),
702 void (*add_history_fun) (const char*),
703 int (*rw_history_fun)(const char *, int, int))
705 my_rl_init_stream = init_stream;
706 my_rl_set_completer = set_completer;
707 my_rl_inhibit_completion = inhibit_completion;
708 my_rl_cleanup_after_signal = cleanup_after_signal;
709 my_rl_readline = readline_fun;
710 my_rl_add_history = add_history_fun;
711 my_rl_rw_history = rw_history_fun;
715 /* Read the history from FILENAME or limit the size of the history.
716 * If FILENAME is NULL and NLINES is zero the current history is
717 * cleared. Returns 0 on success or -1 on error and sets ERRNO. No
718 * error is return if readline support is not available. */
720 tty_read_history (const char *filename, int nlines)
724 if (!my_rl_rw_history)
727 rc = my_rl_rw_history (filename, 0, nlines);
728 if (rc && gpg_err_code_from_syserror () == GPG_ERR_ENOENT)
735 /* Write the current history to the file FILENAME. Returns 0 on
736 * success or -1 on error and sets ERRNO. No error is return if
737 * readline support is not available. */
739 tty_write_history (const char *filename)
741 if (!my_rl_rw_history)
744 return my_rl_rw_history (filename, 1, 0);
748 #ifdef HAVE_LIBREADLINE
750 tty_enable_completion (rl_completion_func_t *completer)
752 if (no_terminal || !my_rl_set_completer )
758 my_rl_set_completer (completer);
762 tty_disable_completion (void)
764 if (no_terminal || !my_rl_inhibit_completion)
770 my_rl_inhibit_completion (1);
772 #endif /* HAVE_LIBREADLINE */
775 tty_cleanup_after_signal (void)
777 #ifdef HAVE_TCGETATTR
783 tty_cleanup_rl_after_signal (void)
785 if (my_rl_cleanup_after_signal)
786 my_rl_cleanup_after_signal ();