LCOV - code coverage report
Current view: top level - src/common - sprompt.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 23 35 65.7 %
Date: 2024-04-25 12:11:11 Functions: 1 2 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * sprompt.c
       4             :  *    simple_prompt() routine
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, 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           4 : 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           4 :     termin = fopen("/dev/tty", "r");
      96           4 :     termout = fopen("/dev/tty", "w");
      97             : #endif
      98           4 :     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           4 :     if (!echo)
     120             :     {
     121             : #if defined(HAVE_TERMIOS_H)
     122             :         /* disable echo via tcgetattr/tcsetattr */
     123           4 :         tcgetattr(fileno(termin), &t);
     124           4 :         t_orig = t;
     125           4 :         t.c_lflag &= ~ECHO;
     126           4 :         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           4 :     if (prompt)
     140             :     {
     141           4 :         fputs(_(prompt), termout);
     142           4 :         fflush(termout);
     143             :     }
     144             : 
     145           4 :     result = pg_get_line(termin, prompt_ctx);
     146             : 
     147             :     /* If we failed to read anything, just return an empty string */
     148           4 :     if (result == NULL)
     149           0 :         result = pg_strdup("");
     150             : 
     151             :     /* strip trailing newline, including \r in case we're on Windows */
     152           4 :     (void) pg_strip_crlf(result);
     153             : 
     154           4 :     if (!echo)
     155             :     {
     156             :         /* restore previous echo behavior, then echo \n */
     157             : #if defined(HAVE_TERMIOS_H)
     158           4 :         tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
     159           4 :         fputs("\n", termout);
     160           4 :         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           4 :     if (termin != stdin)
     175             :     {
     176           4 :         fclose(termin);
     177           4 :         fclose(termout);
     178             :     }
     179             : 
     180           4 :     return result;
     181             : }

Generated by: LCOV version 1.14