LCOV - code coverage report
Current view: top level - src/common - sprompt.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 65.7 % 35 23
Test Date: 2026-03-12 06:14:44 Functions: 50.0 % 2 1
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * sprompt.c
       4              :  *    simple_prompt() routine
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/common/sprompt.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "c.h"
      16              : 
      17              : #include "common/fe_memutils.h"
      18              : #include "common/string.h"
      19              : 
      20              : #ifdef HAVE_TERMIOS_H
      21              : #include <termios.h>
      22              : #endif
      23              : 
      24              : 
      25              : /*
      26              :  * simple_prompt
      27              :  *
      28              :  * Generalized function especially intended for reading in usernames and
      29              :  * passwords interactively.  Reads from /dev/tty or stdin/stderr.
      30              :  *
      31              :  * prompt:      The prompt to print, or NULL if none (automatically localized)
      32              :  * echo:        Set to false if you want to hide what is entered (for passwords)
      33              :  *
      34              :  * The input (without trailing newline) is returned as a malloc'd string.
      35              :  * Caller is responsible for freeing it when done.
      36              :  */
      37              : char *
      38            0 : simple_prompt(const char *prompt, bool echo)
      39              : {
      40            0 :     return simple_prompt_extended(prompt, echo, NULL);
      41              : }
      42              : 
      43              : /*
      44              :  * simple_prompt_extended
      45              :  *
      46              :  * This is the same as simple_prompt(), except that prompt_ctx can
      47              :  * optionally be provided to allow this function to be canceled via an
      48              :  * existing SIGINT signal handler that will longjmp to the specified place
      49              :  * only when *(prompt_ctx->enabled) is true.  If canceled, this function
      50              :  * returns an empty string, and prompt_ctx->canceled is set to true.
      51              :  */
      52              : char *
      53            2 : simple_prompt_extended(const char *prompt, bool echo,
      54              :                        PromptInterruptContext *prompt_ctx)
      55              : {
      56              :     char       *result;
      57              :     FILE       *termin,
      58              :                *termout;
      59              : #if defined(HAVE_TERMIOS_H)
      60              :     struct termios t_orig,
      61              :                 t;
      62              : #elif defined(WIN32)
      63              :     HANDLE      t = NULL;
      64              :     DWORD       t_orig = 0;
      65              : #endif
      66              : 
      67              : #ifdef WIN32
      68              : 
      69              :     /*
      70              :      * A Windows console has an "input code page" and an "output code page";
      71              :      * these usually match each other, but they rarely match the "Windows ANSI
      72              :      * code page" defined at system boot and expected of "char *" arguments to
      73              :      * Windows API functions.  The Microsoft CRT write() implementation
      74              :      * automatically converts text between these code pages when writing to a
      75              :      * console.  To identify such file descriptors, it calls GetConsoleMode()
      76              :      * on the underlying HANDLE, which in turn requires GENERIC_READ access on
      77              :      * the HANDLE.  Opening termout in mode "w+" allows that detection to
      78              :      * succeed.  Otherwise, write() would not recognize the descriptor as a
      79              :      * console, and non-ASCII characters would display incorrectly.
      80              :      *
      81              :      * XXX fgets() still receives text in the console's input code page.  This
      82              :      * makes non-ASCII credentials unportable.
      83              :      *
      84              :      * Unintuitively, we also open termin in mode "w+", even though we only
      85              :      * read it; that's needed for SetConsoleMode() to succeed.
      86              :      */
      87              :     termin = fopen("CONIN$", "w+");
      88              :     termout = fopen("CONOUT$", "w+");
      89              : #else
      90              : 
      91              :     /*
      92              :      * Do not try to collapse these into one "w+" mode file. Doesn't work on
      93              :      * some platforms (eg, HPUX 10.20).
      94              :      */
      95            2 :     termin = fopen("/dev/tty", "r");
      96            2 :     termout = fopen("/dev/tty", "w");
      97              : #endif
      98            2 :     if (!termin || !termout
      99              : #ifdef WIN32
     100              : 
     101              :     /*
     102              :      * Direct console I/O does not work from the MSYS 1.0.10 console.  Writes
     103              :      * reach nowhere user-visible; reads block indefinitely.  XXX This affects
     104              :      * most Windows terminal environments, including rxvt, mintty, Cygwin
     105              :      * xterm, Cygwin sshd, and PowerShell ISE.  Switch to a more-generic test.
     106              :      */
     107              :         || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
     108              : #endif
     109              :         )
     110              :     {
     111            0 :         if (termin)
     112            0 :             fclose(termin);
     113            0 :         if (termout)
     114            0 :             fclose(termout);
     115            0 :         termin = stdin;
     116            0 :         termout = stderr;
     117              :     }
     118              : 
     119            2 :     if (!echo)
     120              :     {
     121              : #if defined(HAVE_TERMIOS_H)
     122              :         /* disable echo via tcgetattr/tcsetattr */
     123            2 :         tcgetattr(fileno(termin), &t);
     124            2 :         t_orig = t;
     125            2 :         t.c_lflag &= ~ECHO;
     126            2 :         tcsetattr(fileno(termin), TCSAFLUSH, &t);
     127              : #elif defined(WIN32)
     128              :         /* need the file's HANDLE to turn echo off */
     129              :         t = (HANDLE) _get_osfhandle(_fileno(termin));
     130              : 
     131              :         /* save the old configuration first */
     132              :         GetConsoleMode(t, &t_orig);
     133              : 
     134              :         /* set to the new mode */
     135              :         SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
     136              : #endif
     137              :     }
     138              : 
     139            2 :     if (prompt)
     140              :     {
     141            2 :         fputs(_(prompt), termout);
     142            2 :         fflush(termout);
     143              :     }
     144              : 
     145            2 :     result = pg_get_line(termin, prompt_ctx);
     146              : 
     147              :     /* If we failed to read anything, just return an empty string */
     148            2 :     if (result == NULL)
     149            0 :         result = pg_strdup("");
     150              : 
     151              :     /* strip trailing newline, including \r in case we're on Windows */
     152            2 :     (void) pg_strip_crlf(result);
     153              : 
     154            2 :     if (!echo)
     155              :     {
     156              :         /* restore previous echo behavior, then echo \n */
     157              : #if defined(HAVE_TERMIOS_H)
     158            2 :         tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
     159            2 :         fputs("\n", termout);
     160            2 :         fflush(termout);
     161              : #elif defined(WIN32)
     162              :         SetConsoleMode(t, t_orig);
     163              :         fputs("\n", termout);
     164              :         fflush(termout);
     165              : #endif
     166              :     }
     167            0 :     else if (prompt_ctx && prompt_ctx->canceled)
     168              :     {
     169              :         /* also echo \n if prompt was canceled */
     170            0 :         fputs("\n", termout);
     171            0 :         fflush(termout);
     172              :     }
     173              : 
     174            2 :     if (termin != stdin)
     175              :     {
     176            2 :         fclose(termin);
     177            2 :         fclose(termout);
     178              :     }
     179              : 
     180            2 :     return result;
     181              : }
        

Generated by: LCOV version 2.0-1