Re: psql: default base and password reading - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: psql: default base and password reading
Date
Msg-id 200110131714.f9DHEWA21586@candle.pha.pa.us
Whole thread Raw
In response to Re: psql: default base and password reading  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> >> On second thought --- are we creating any portability problems if we
> >> assume /dev/tty exists?  In particular, what about the Windows port
> >> of psql?  Will it still work?
>
> > I am sure cygwin takes care of this.
>
> Please recall that we have a *native* port of psql ... cygwin doesn't
> help.

OK, I read up on how BSD/OS does this and found getpass():

     The getpass() function displays a prompt to, and reads in a password
     from, /dev/tty. If this file is not accessible, getpass displays the
     prompt on the standard error output and reads from the standard
     input.

So even it tries for /dev/tty and falls back to stdin/stderr.  The
attached patch does this.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
Index: src/bin/pg_dump/pg_backup_db.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v
retrieving revision 1.26
diff -c -r1.26 pg_backup_db.c
*** src/bin/pg_dump/pg_backup_db.c    2001/09/21 21:58:30    1.26
--- src/bin/pg_dump/pg_backup_db.c    2001/10/13 17:10:07
***************
*** 49,55 ****
   * simple_prompt
   *
   * Generalized function especially intended for reading in usernames and
!  * password interactively. Reads from stdin.
   *
   * prompt:        The prompt to print
   * maxlen:        How many characters to accept
--- 49,55 ----
   * simple_prompt
   *
   * Generalized function especially intended for reading in usernames and
!  * password interactively. Reads from /dev/tty or stdin/stderr.
   *
   * prompt:        The prompt to print
   * maxlen:        How many characters to accept
***************
*** 57,101 ****
   *
   * Returns a malloc()'ed string with the input (w/o trailing newline).
   */
  char *
  simple_prompt(const char *prompt, int maxlen, bool echo)
  {
      int            length;
      char       *destination;

  #ifdef HAVE_TERMIOS_H
      struct termios t_orig,
                  t;
-
  #endif

      destination = (char *) malloc(maxlen + 2);
      if (!destination)
          return NULL;
      if (prompt)
!         fputs(gettext(prompt), stderr);

  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcgetattr(0, &t);
          t_orig = t;
          t.c_lflag &= ~ECHO;
!         tcsetattr(0, TCSADRAIN, &t);
      }
  #endif

!     if (fgets(destination, maxlen, stdin) == NULL)
          destination[0] = '\0';

  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcsetattr(0, TCSADRAIN, &t_orig);
!         fputs("\n", stderr);
      }
  #endif

      length = strlen(destination);
      if (length > 0 && destination[length - 1] != '\n')
      {
--- 57,121 ----
   *
   * Returns a malloc()'ed string with the input (w/o trailing newline).
   */
+ static bool prompt_state;
+
  char *
  simple_prompt(const char *prompt, int maxlen, bool echo)
  {
      int            length;
      char       *destination;
+     static FILE *termin = NULL, *termout;

  #ifdef HAVE_TERMIOS_H
      struct termios t_orig,
                  t;
  #endif

      destination = (char *) malloc(maxlen + 2);
      if (!destination)
          return NULL;
+
+     prompt_state = true;
+
+     /* initialize the streams */
+     if (!termin)
+     {
+         if ((termin = termout = fopen("/dev/tty", "w+")) == NULL)
+         {
+             termin = stdin;
+             termout = stderr;
+         }
+     }
+
      if (prompt)
!     {
!         fputs(gettext(prompt), termout);
!         rewind(termout); /* does flush too */
!     }

  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcgetattr(fileno(termin), &t);
          t_orig = t;
          t.c_lflag &= ~ECHO;
!         tcsetattr(fileno(termin), TCSADRAIN, &t);
      }
  #endif

!     if (fgets(destination, maxlen, termin) == NULL)
          destination[0] = '\0';

  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcsetattr(fileno(termin), TCSADRAIN, &t_orig);
!         fputs("\n", termout);
      }
  #endif

+     prompt_state = false;
+
      length = strlen(destination);
      if (length > 0 && destination[length - 1] != '\n')
      {
***************
*** 105,121 ****

          do
          {
!             if (fgets(buf, sizeof(buf), stdin) == NULL)
                  break;
              buflen = strlen(buf);
          } while (buflen > 0 && buf[buflen - 1] != '\n');
      }
      if (length > 0 && destination[length - 1] == '\n')
          /* remove trailing newline */
          destination[length - 1] = '\0';

      return destination;
  }


  static int
--- 125,143 ----

          do
          {
!             if (fgets(buf, sizeof(buf), termin) == NULL)
                  break;
              buflen = strlen(buf);
          } while (buflen > 0 && buf[buflen - 1] != '\n');
      }
+
      if (length > 0 && destination[length - 1] == '\n')
          /* remove trailing newline */
          destination[length - 1] = '\0';

      return destination;
  }
+


  static int
Index: src/bin/psql/common.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/common.c,v
retrieving revision 1.34
diff -c -r1.34 common.c
*** src/bin/psql/common.c    2001/06/08 23:53:48    1.34
--- src/bin/psql/common.c    2001/10/13 17:10:11
***************
*** 161,167 ****
   * simple_prompt
   *
   * Generalized function especially intended for reading in usernames and
!  * password interactively. Reads from stdin.
   *
   * prompt:        The prompt to print
   * maxlen:        How many characters to accept
--- 161,167 ----
   * simple_prompt
   *
   * Generalized function especially intended for reading in usernames and
!  * password interactively. Reads from /dev/tty or stdin/stderr.
   *
   * prompt:        The prompt to print
   * maxlen:        How many characters to accept
***************
*** 176,214 ****
  {
      int            length;
      char       *destination;

  #ifdef HAVE_TERMIOS_H
      struct termios t_orig,
                  t;
-
  #endif

      destination = (char *) malloc(maxlen + 2);
      if (!destination)
          return NULL;
-     if (prompt)
-         fputs(gettext(prompt), stderr);

      prompt_state = true;

  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcgetattr(0, &t);
          t_orig = t;
          t.c_lflag &= ~ECHO;
!         tcsetattr(0, TCSADRAIN, &t);
      }
  #endif

!     if (fgets(destination, maxlen, stdin) == NULL)
          destination[0] = '\0';

  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcsetattr(0, TCSADRAIN, &t_orig);
!         fputs("\n", stderr);
      }
  #endif

--- 176,228 ----
  {
      int            length;
      char       *destination;
+     static FILE *termin = NULL, *termout;

  #ifdef HAVE_TERMIOS_H
      struct termios t_orig,
                  t;
  #endif

      destination = (char *) malloc(maxlen + 2);
      if (!destination)
          return NULL;

      prompt_state = true;

+     /* initialize the streams */
+     if (!termin)
+     {
+         if ((termin = termout = fopen("/dev/tty", "w+")) == NULL)
+         {
+             termin = stdin;
+             termout = stderr;
+         }
+     }
+
+     if (prompt)
+     {
+         fputs(gettext(prompt), termout);
+         rewind(termout); /* does flush too */
+     }
+
  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcgetattr(fileno(termin), &t);
          t_orig = t;
          t.c_lflag &= ~ECHO;
!         tcsetattr(fileno(termin), TCSADRAIN, &t);
      }
  #endif

!     if (fgets(destination, maxlen, termin) == NULL)
          destination[0] = '\0';

  #ifdef HAVE_TERMIOS_H
      if (!echo)
      {
!         tcsetattr(fileno(termin), TCSADRAIN, &t_orig);
!         fputs("\n", termout);
      }
  #endif

***************
*** 223,229 ****

          do
          {
!             if (fgets(buf, sizeof(buf), stdin) == NULL)
                  break;
              buflen = strlen(buf);
          } while (buflen > 0 && buf[buflen - 1] != '\n');
--- 237,243 ----

          do
          {
!             if (fgets(buf, sizeof(buf), termin) == NULL)
                  break;
              buflen = strlen(buf);
          } while (buflen > 0 && buf[buflen - 1] != '\n');

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: psql: default base and password reading
Next
From: Peter Eisentraut
Date:
Subject: Re: psql: default base and password reading