Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * sprompt.c
4 : * simple_prompt() routine
5 : *
6 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/port/sprompt.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "c.h"
16 :
17 : #ifdef HAVE_TERMIOS_H
18 : #include <termios.h>
19 : #endif
20 :
21 :
22 : /*
23 : * simple_prompt
24 : *
25 : * Generalized function especially intended for reading in usernames and
26 : * passwords interactively. Reads from /dev/tty or stdin/stderr.
27 : *
28 : * prompt: The prompt to print, or NULL if none (automatically localized)
29 : * destination: buffer in which to store result
30 : * destlen: allocated length of destination
31 : * echo: Set to false if you want to hide what is entered (for passwords)
32 : *
33 : * The input (without trailing newline) is returned in the destination buffer,
34 : * with a '\0' appended.
35 : */
36 : void
37 0 : simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
38 : {
39 : int length;
40 : FILE *termin,
41 : *termout;
42 :
43 : #ifdef HAVE_TERMIOS_H
44 : struct termios t_orig,
45 : t;
46 : #else
47 : #ifdef WIN32
48 : HANDLE t = NULL;
49 : DWORD t_orig = 0;
50 : #endif
51 : #endif
52 :
53 : #ifdef WIN32
54 :
55 : /*
56 : * A Windows console has an "input code page" and an "output code page";
57 : * these usually match each other, but they rarely match the "Windows ANSI
58 : * code page" defined at system boot and expected of "char *" arguments to
59 : * Windows API functions. The Microsoft CRT write() implementation
60 : * automatically converts text between these code pages when writing to a
61 : * console. To identify such file descriptors, it calls GetConsoleMode()
62 : * on the underlying HANDLE, which in turn requires GENERIC_READ access on
63 : * the HANDLE. Opening termout in mode "w+" allows that detection to
64 : * succeed. Otherwise, write() would not recognize the descriptor as a
65 : * console, and non-ASCII characters would display incorrectly.
66 : *
67 : * XXX fgets() still receives text in the console's input code page. This
68 : * makes non-ASCII credentials unportable.
69 : */
70 : termin = fopen("CONIN$", "r");
71 : termout = fopen("CONOUT$", "w+");
72 : #else
73 :
74 : /*
75 : * Do not try to collapse these into one "w+" mode file. Doesn't work on
76 : * some platforms (eg, HPUX 10.20).
77 : */
78 0 : termin = fopen("/dev/tty", "r");
79 0 : termout = fopen("/dev/tty", "w");
80 : #endif
81 0 : if (!termin || !termout
82 : #ifdef WIN32
83 :
84 : /*
85 : * Direct console I/O does not work from the MSYS 1.0.10 console. Writes
86 : * reach nowhere user-visible; reads block indefinitely. XXX This affects
87 : * most Windows terminal environments, including rxvt, mintty, Cygwin
88 : * xterm, Cygwin sshd, and PowerShell ISE. Switch to a more-generic test.
89 : */
90 : || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
91 : #endif
92 : )
93 : {
94 0 : if (termin)
95 0 : fclose(termin);
96 0 : if (termout)
97 0 : fclose(termout);
98 0 : termin = stdin;
99 0 : termout = stderr;
100 : }
101 :
102 : #ifdef HAVE_TERMIOS_H
103 0 : if (!echo)
104 : {
105 0 : tcgetattr(fileno(termin), &t);
106 0 : t_orig = t;
107 0 : t.c_lflag &= ~ECHO;
108 0 : tcsetattr(fileno(termin), TCSAFLUSH, &t);
109 : }
110 : #else
111 : #ifdef WIN32
112 : if (!echo)
113 : {
114 : /* get a new handle to turn echo off */
115 : t = GetStdHandle(STD_INPUT_HANDLE);
116 :
117 : /* save the old configuration first */
118 : GetConsoleMode(t, &t_orig);
119 :
120 : /* set to the new mode */
121 : SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
122 : }
123 : #endif
124 : #endif
125 :
126 0 : if (prompt)
127 : {
128 0 : fputs(_(prompt), termout);
129 0 : fflush(termout);
130 : }
131 :
132 0 : if (fgets(destination, destlen, termin) == NULL)
133 0 : destination[0] = '\0';
134 :
135 0 : length = strlen(destination);
136 0 : if (length > 0 && destination[length - 1] != '\n')
137 : {
138 : /* eat rest of the line */
139 : char buf[128];
140 : int buflen;
141 :
142 : do
143 : {
144 0 : if (fgets(buf, sizeof(buf), termin) == NULL)
145 0 : break;
146 0 : buflen = strlen(buf);
147 0 : } while (buflen > 0 && buf[buflen - 1] != '\n');
148 : }
149 :
150 0 : if (length > 0 && destination[length - 1] == '\n')
151 : /* remove trailing newline */
152 0 : destination[length - 1] = '\0';
153 :
154 : #ifdef HAVE_TERMIOS_H
155 0 : if (!echo)
156 : {
157 0 : tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
158 0 : fputs("\n", termout);
159 0 : fflush(termout);
160 : }
161 : #else
162 : #ifdef WIN32
163 : if (!echo)
164 : {
165 : /* reset to the original console mode */
166 : SetConsoleMode(t, t_orig);
167 : fputs("\n", termout);
168 : fflush(termout);
169 : }
170 : #endif
171 : #endif
172 :
173 0 : if (termin != stdin)
174 : {
175 0 : fclose(termin);
176 0 : fclose(termout);
177 : }
178 0 : }
|