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