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