/Users/deen/code/yugabyte-db/src/postgres/src/port/sprompt.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * sprompt.c |
4 | | * simple_prompt() routine |
5 | | * |
6 | | * Portions Copyright (c) 1996-2018, 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 | | simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo) |
38 | 0 | { |
39 | 0 | int length; |
40 | 0 | FILE *termin, |
41 | 0 | *termout; |
42 | |
|
43 | 0 | #if defined(HAVE_TERMIOS_H) |
44 | 0 | struct termios t_orig, |
45 | 0 | t; |
46 | | #elif defined(WIN32) |
47 | | HANDLE t = NULL; |
48 | | DWORD t_orig = 0; |
49 | | #endif |
50 | |
|
51 | | #ifdef WIN32 |
52 | | |
53 | | /* |
54 | | * A Windows console has an "input code page" and an "output code page"; |
55 | | * these usually match each other, but they rarely match the "Windows ANSI |
56 | | * code page" defined at system boot and expected of "char *" arguments to |
57 | | * Windows API functions. The Microsoft CRT write() implementation |
58 | | * automatically converts text between these code pages when writing to a |
59 | | * console. To identify such file descriptors, it calls GetConsoleMode() |
60 | | * on the underlying HANDLE, which in turn requires GENERIC_READ access on |
61 | | * the HANDLE. Opening termout in mode "w+" allows that detection to |
62 | | * succeed. Otherwise, write() would not recognize the descriptor as a |
63 | | * console, and non-ASCII characters would display incorrectly. |
64 | | * |
65 | | * XXX fgets() still receives text in the console's input code page. This |
66 | | * makes non-ASCII credentials unportable. |
67 | | * |
68 | | * Unintuitively, we also open termin in mode "w+", even though we only |
69 | | * read it; that's needed for SetConsoleMode() to succeed. |
70 | | */ |
71 | | termin = fopen("CONIN$", "w+"); |
72 | | termout = fopen("CONOUT$", "w+"); |
73 | | #else |
74 | | |
75 | | /* |
76 | | * Do not try to collapse these into one "w+" mode file. Doesn't work on |
77 | | * some platforms (eg, HPUX 10.20). |
78 | | */ |
79 | 0 | termin = fopen("/dev/tty", "r"); |
80 | 0 | termout = fopen("/dev/tty", "w"); |
81 | 0 | #endif |
82 | 0 | if (!termin || !termout |
83 | | #ifdef WIN32 |
84 | | |
85 | | /* |
86 | | * Direct console I/O does not work from the MSYS 1.0.10 console. Writes |
87 | | * reach nowhere user-visible; reads block indefinitely. XXX This affects |
88 | | * most Windows terminal environments, including rxvt, mintty, Cygwin |
89 | | * xterm, Cygwin sshd, and PowerShell ISE. Switch to a more-generic test. |
90 | | */ |
91 | | || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0) |
92 | | #endif |
93 | 0 | ) |
94 | 0 | { |
95 | 0 | if (termin) |
96 | 0 | fclose(termin); |
97 | 0 | if (termout) |
98 | 0 | fclose(termout); |
99 | 0 | termin = stdin; |
100 | 0 | termout = stderr; |
101 | 0 | } |
102 | |
|
103 | 0 | if (!echo) |
104 | 0 | { |
105 | 0 | #if defined(HAVE_TERMIOS_H) |
106 | | /* disable echo via tcgetattr/tcsetattr */ |
107 | 0 | tcgetattr(fileno(termin), &t); |
108 | 0 | t_orig = t; |
109 | 0 | t.c_lflag &= ~ECHO; |
110 | 0 | tcsetattr(fileno(termin), TCSAFLUSH, &t); |
111 | | #elif defined(WIN32) |
112 | | /* need the file's HANDLE to turn echo off */ |
113 | | t = (HANDLE) _get_osfhandle(_fileno(termin)); |
114 | | |
115 | | /* save the old configuration first */ |
116 | | GetConsoleMode(t, &t_orig); |
117 | | |
118 | | /* set to the new mode */ |
119 | | SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); |
120 | | #endif |
121 | 0 | } |
122 | |
|
123 | 0 | if (prompt) |
124 | 0 | { |
125 | 0 | fputs(_(prompt), termout); |
126 | 0 | fflush(termout); |
127 | 0 | } |
128 | |
|
129 | 0 | if (fgets(destination, destlen, termin) == NULL) |
130 | 0 | destination[0] = '\0'; |
131 | |
|
132 | 0 | length = strlen(destination); |
133 | 0 | if (length > 0 && destination[length - 1] != '\n') |
134 | 0 | { |
135 | | /* eat rest of the line */ |
136 | 0 | char buf[128]; |
137 | 0 | int buflen; |
138 | |
|
139 | 0 | do |
140 | 0 | { |
141 | 0 | if (fgets(buf, sizeof(buf), termin) == NULL) |
142 | 0 | break; |
143 | 0 | buflen = strlen(buf); |
144 | 0 | } while (buflen > 0 && buf[buflen - 1] != '\n'); |
145 | 0 | } |
146 | | |
147 | 0 | if (length > 0 && destination[length - 1] == '\n') |
148 | | /* remove trailing newline */ |
149 | 0 | destination[length - 1] = '\0'; |
150 | |
|
151 | 0 | if (!echo) |
152 | 0 | { |
153 | | /* restore previous echo behavior, then echo \n */ |
154 | 0 | #if defined(HAVE_TERMIOS_H) |
155 | 0 | tcsetattr(fileno(termin), TCSAFLUSH, &t_orig); |
156 | 0 | fputs("\n", termout); |
157 | 0 | fflush(termout); |
158 | | #elif defined(WIN32) |
159 | | SetConsoleMode(t, t_orig); |
160 | | fputs("\n", termout); |
161 | | fflush(termout); |
162 | | #endif |
163 | 0 | } |
164 | |
|
165 | 0 | if (termin != stdin) |
166 | 0 | { |
167 | 0 | fclose(termin); |
168 | 0 | fclose(termout); |
169 | 0 | } |
170 | 0 | } |