LCOV - differential code coverage report
Current view: top level - src/common - sprompt.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 65.7 % 35 23 12 23
Current Date: 2023-04-08 15:15:32 Functions: 50.0 % 2 1 1 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * sprompt.c
       4                 :  *    simple_prompt() routine
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, 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 UBC           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 CBC           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 UBC           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 CBC           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 UBC           0 :         result = pg_strdup("");
     150                 : 
     151                 :     /* strip trailing newline, including \r in case we're on Windows */
     152 CBC           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 UBC           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 CBC           2 :     if (termin != stdin)
     175                 :     {
     176               2 :         fclose(termin);
     177               2 :         fclose(termout);
     178                 :     }
     179                 : 
     180               2 :     return result;
     181                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a