]> granicus.if.org Git - postgresql/blob - src/port/sprompt.c
Make psql reject attempts to set special variables to invalid values.
[postgresql] / src / port / sprompt.c
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 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         termin = fopen("/dev/tty", "r");
79         termout = fopen("/dev/tty", "w");
80 #endif
81         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                 if (termin)
95                         fclose(termin);
96                 if (termout)
97                         fclose(termout);
98                 termin = stdin;
99                 termout = stderr;
100         }
101
102 #ifdef HAVE_TERMIOS_H
103         if (!echo)
104         {
105                 tcgetattr(fileno(termin), &t);
106                 t_orig = t;
107                 t.c_lflag &= ~ECHO;
108                 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         if (prompt)
127         {
128                 fputs(_(prompt), termout);
129                 fflush(termout);
130         }
131
132         if (fgets(destination, destlen, termin) == NULL)
133                 destination[0] = '\0';
134
135         length = strlen(destination);
136         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                         if (fgets(buf, sizeof(buf), termin) == NULL)
145                                 break;
146                         buflen = strlen(buf);
147                 } while (buflen > 0 && buf[buflen - 1] != '\n');
148         }
149
150         if (length > 0 && destination[length - 1] == '\n')
151                 /* remove trailing newline */
152                 destination[length - 1] = '\0';
153
154 #ifdef HAVE_TERMIOS_H
155         if (!echo)
156         {
157                 tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
158                 fputs("\n", termout);
159                 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         if (termin != stdin)
174         {
175                 fclose(termin);
176                 fclose(termout);
177         }
178 }