1414#include "getopt_long.h"
1515#include <limits.h>
1616#include <time.h>
17- #include <stdio.h>
1817#include <unistd.h>
1918
20- #ifdef HAVE_TERMIOS_H
21- #include <termios.h>
22- #endif
23-
2419#include "logger.h"
2520#include "pgut.h"
2621
@@ -52,6 +47,7 @@ static PGcancel *volatile cancel_conn = NULL;
5247/* Interrupted by SIGINT (Ctrl+C) ? */
5348bool interrupted = false;
5449bool in_cleanup = false;
50+ bool in_password = false;
5551
5652static bool parse_pair (const char buffer [], char key [], char value []);
5753
@@ -1285,235 +1281,6 @@ parse_pair(const char buffer[], char key[], char value[])
12851281 return true;
12861282}
12871283
1288- /*
1289- * pgut_prompt
1290- *
1291- * Generalized function especially intended for reading in usernames and
1292- * passwords interactively. Reads from /dev/tty or stdin/stderr.
1293- *
1294- * prompt: The prompt to print, or NULL if none (automatically localized)
1295- * destination: buffer in which to store result
1296- * destlen: allocated length of destination
1297- * echo: Set to false if you want to hide what is entered (for passwords)
1298- *
1299- * The input (without trailing newline) is returned in the destination buffer,
1300- * with a '\0' appended.
1301- *
1302- * Copy of simple_prompt().
1303- */
1304- static void
1305- pgut_prompt (const char * prompt , char * destination , size_t destlen , bool echo )
1306- {
1307- size_t length = 0 ;
1308- char * ptr = destination ;
1309- FILE * termin ,
1310- * termout ;
1311- bool exit_with_error = false;
1312-
1313- #ifdef HAVE_TERMIOS_H
1314- struct termios t_orig ,
1315- t ;
1316- #else
1317- #ifdef WIN32
1318- HANDLE t = NULL ;
1319- DWORD t_orig = 0 ;
1320- #endif
1321- #endif
1322-
1323- #ifdef WIN32
1324-
1325- /*
1326- * A Windows console has an "input code page" and an "output code page";
1327- * these usually match each other, but they rarely match the "Windows ANSI
1328- * code page" defined at system boot and expected of "char *" arguments to
1329- * Windows API functions. The Microsoft CRT write() implementation
1330- * automatically converts text between these code pages when writing to a
1331- * console. To identify such file descriptors, it calls GetConsoleMode()
1332- * on the underlying HANDLE, which in turn requires GENERIC_READ access on
1333- * the HANDLE. Opening termout in mode "w+" allows that detection to
1334- * succeed. Otherwise, write() would not recognize the descriptor as a
1335- * console, and non-ASCII characters would display incorrectly.
1336- *
1337- * XXX fgets() still receives text in the console's input code page. This
1338- * makes non-ASCII credentials unportable.
1339- */
1340- termin = fopen ("CONIN$" , "r" );
1341- termout = fopen ("CONOUT$" , "w+" );
1342- #else
1343-
1344- /*
1345- * Do not try to collapse these into one "w+" mode file. Doesn't work on
1346- * some platforms (eg, HPUX 10.20).
1347- */
1348- termin = fopen ("/dev/tty" , "r" );
1349- termout = fopen ("/dev/tty" , "w" );
1350- #endif
1351- if (!termin || !termout
1352- #ifdef WIN32
1353-
1354- /*
1355- * Direct console I/O does not work from the MSYS 1.0.10 console. Writes
1356- * reach nowhere user-visible; reads block indefinitely. XXX This affects
1357- * most Windows terminal environments, including rxvt, mintty, Cygwin
1358- * xterm, Cygwin sshd, and PowerShell ISE. Switch to a more-generic test.
1359- */
1360- || (getenv ("OSTYPE" ) && strcmp (getenv ("OSTYPE" ), "msys" ) == 0 )
1361- #endif
1362- )
1363- {
1364- if (termin )
1365- fclose (termin );
1366- if (termout )
1367- fclose (termout );
1368- termin = stdin ;
1369- termout = stderr ;
1370- }
1371-
1372- #ifdef HAVE_TERMIOS_H
1373- if (!echo )
1374- {
1375- tcgetattr (fileno (termin ), & t );
1376- t_orig = t ;
1377- t .c_lflag &= ~ECHO ;
1378- tcsetattr (fileno (termin ), TCSAFLUSH , & t );
1379- }
1380- #else
1381- #ifdef WIN32
1382- if (!echo )
1383- {
1384- /* get a new handle to turn echo off */
1385- t = GetStdHandle (STD_INPUT_HANDLE );
1386-
1387- /* save the old configuration first */
1388- GetConsoleMode (t , & t_orig );
1389-
1390- /* set to the new mode */
1391- SetConsoleMode (t , ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT );
1392- }
1393- #endif
1394- #endif
1395-
1396- if (!pg_set_noblock (fileno (termin )))
1397- elog (ERROR , "could not set terminal to nonblocking mode" );
1398-
1399- if (prompt )
1400- {
1401- fputs (_ (prompt ), termout );
1402- fflush (termout );
1403- }
1404-
1405- if (interrupted )
1406- {
1407- exit_with_error = true;
1408- goto cleanup ;
1409- }
1410-
1411- do
1412- {
1413- int selres ;
1414- struct timeval timeout ;
1415-
1416- timeout .tv_sec = 0 ;
1417- timeout .tv_usec = 100 * 1000L ; /* 100 milliseconds */
1418-
1419- selres = wait_for_socket (fileno (termin ), & timeout );
1420- if (selres < 0 || interrupted )
1421- {
1422- exit_with_error = true;
1423- goto cleanup ;
1424- }
1425-
1426- if (selres > 0 )
1427- {
1428- size_t len = fread (ptr , sizeof (char ), destlen - length , termin );
1429-
1430- if (len <= 0 )
1431- {
1432- exit_with_error = true;
1433- goto cleanup ;
1434- }
1435-
1436- length += len ;
1437- ptr += len ;
1438- }
1439-
1440- if (length > 0 && destination [length - 1 ] == '\n' )
1441- break ;
1442- } while (length < destlen );
1443-
1444- if (length > 0 && destination [length - 1 ] != '\n' )
1445- {
1446- /* eat rest of the line */
1447- int selres ;
1448- struct timeval timeout ;
1449-
1450- while (true)
1451- {
1452- timeout .tv_sec = 0 ;
1453- timeout .tv_usec = 100 * 1000L ; /* 100 milliseconds */
1454-
1455- selres = wait_for_socket (fileno (termin ), & timeout );
1456- if (selres < 0 || interrupted )
1457- {
1458- exit_with_error = true;
1459- goto cleanup ;
1460- }
1461-
1462- if (selres > 0 )
1463- {
1464- char buf [128 ];
1465- size_t len = fread (buf , sizeof (char ), sizeof (buf ), termin );
1466-
1467- if (len <= 0 )
1468- {
1469- exit_with_error = true;
1470- goto cleanup ;
1471- }
1472-
1473- if (buf [len - 1 ] == '\n' )
1474- break ;
1475- }
1476- }
1477- }
1478-
1479- if (length > 0 && destination [length - 1 ] == '\n' )
1480- /* remove trailing newline */
1481- destination [length - 1 ] = '\0' ;
1482-
1483- cleanup :
1484-
1485- #ifdef HAVE_TERMIOS_H
1486- if (!echo )
1487- {
1488- tcsetattr (fileno (termin ), TCSAFLUSH , & t_orig );
1489- fputs ("\n" , termout );
1490- fflush (termout );
1491- }
1492- #else
1493- #ifdef WIN32
1494- if (!echo )
1495- {
1496- /* reset to the original console mode */
1497- SetConsoleMode (t , t_orig );
1498- fputs ("\n" , termout );
1499- fflush (termout );
1500- }
1501- #endif
1502- #endif
1503-
1504- if (!pg_set_block (fileno (termin )))
1505- elog (ERROR , "could not set terminal to blocking mode" );
1506-
1507- if (termin != stdin )
1508- {
1509- fclose (termin );
1510- fclose (termout );
1511- }
1512-
1513- if (exit_with_error )
1514- exit_or_abort (ERROR );
1515- }
1516-
15171284/*
15181285 * Ask the user for a password; 'username' is the username the
15191286 * password is for, if one has been explicitly specified.
@@ -1522,21 +1289,36 @@ pgut_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
15221289static void
15231290prompt_for_password (const char * username )
15241291{
1292+ in_password = true;
1293+
15251294 if (password )
15261295 {
15271296 free (password );
15281297 password = NULL ;
15291298 }
15301299
1300+ #if PG_VERSION_NUM >= 100000
15311301 password = (char * ) pgut_malloc (sizeof (char ) * 100 + 1 );
15321302 if (username == NULL )
1533- pgut_prompt ("Password: " , password , 100 , false);
1303+ simple_prompt ("Password: " , password , 100 , false);
1304+ else
1305+ {
1306+ char message [256 ];
1307+ snprintf (message , lengthof (message ), "Password for user %s: " , username );
1308+ simple_prompt (message , password , 100 , false);
1309+ }
1310+ #else
1311+ if (username == NULL )
1312+ password = simple_prompt ("Password: " , 100 , false);
15341313 else
15351314 {
15361315 char message [256 ];
15371316 snprintf (message , lengthof (message ), "Password for user %s: " , username );
1538- pgut_prompt (message , password , 100 , false);
1317+ password = simple_prompt (message , 100 , false);
15391318 }
1319+ #endif
1320+
1321+ in_password = false;
15401322}
15411323
15421324PGconn *
@@ -1960,6 +1742,15 @@ on_interrupt(void)
19601742 /* Set interruped flag */
19611743 interrupted = true;
19621744
1745+ /* User promts password, call on_cleanup() byhand */
1746+ if (in_password )
1747+ {
1748+ on_cleanup ();
1749+
1750+ pqsignal (SIGINT , oldhandler );
1751+ kill (0 , SIGINT );
1752+ }
1753+
19631754 /* Send QueryCancel if we are processing a database query */
19641755 if (!in_cleanup && cancel_conn != NULL &&
19651756 PQcancel (cancel_conn , errbuf , sizeof (errbuf )))
0 commit comments