From: Paul Eggert Date: Wed, 8 Oct 2003 20:34:54 +0000 (+0000) Subject: Merge getpass from libc, plus a few fixes. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=64d6ea0ae39513d02468ab04d43e3459a5a0f4ca;p=pspp Merge getpass from libc, plus a few fixes. --- diff --git a/ChangeLog b/ChangeLog index 91f50b6d77..dbd6d166b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-10-08 Paul Eggert + + * modules/getpass: Depend on stdbool. + 2003-10-06 Bruno Haible * modules/version-etc-2: Remove file. diff --git a/lib/ChangeLog b/lib/ChangeLog index 3e95420e5f..2837085702 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,40 @@ +2003-10-08 Paul Eggert + + Merge getpass from libc, plus a few fixes. + + * getpass.c (HAVE_STDIO_EXT) [_LIBC]: Define to 1. + Include . + Include if HAVE_STDIO_H, otherwise define + __fsetlocking to empty. + [_LIBC]: Do not include "getline.h" or "unlocked-io.h", but + do include . + Do not include ; not needed. + [_LIBC]: Include . + (NOTCANCEL_MODE): New macro. + (flockfile, funlockfile) [_LIBC]: New macros. + (__libc_cleanup_push, __libc_cleanup_pop, __getline, __tcgetattr) + [!_LIBC]: New macros. + (call_fclose): New function. + (getpass): Use it. Save tty stream separately; this simplifies the + code and makes it more reliable if stdin happens to equal stdout. + Invoke __fsetlocking on tty. + Handle thread cancellation if needed. + Namespace cleanup (use __tcgetattr, __getline). + Use bool for Booleans. + [USE_IN_LIBIO]: Handle wide streams. + [!_LIBC]: Unconditionally do the fseek, since we don't know what + stream might go where. + + * unlocked-io.h: Include , so that the caller + doesn't have to include before us. + (clearerr_unlocked, feof_unlocked, ferror_unlocked, + fflush_unlocked, fgets_unlocked, fputc_unlocked, fputs_unlocked, + fread_unlocked, fwrite_unlocked, getc_unlocked, getchar_unlocked, + putc_unlocked, putchar_unlocked): Define to the unlocked counterpart + if not declared, so that we can use getpass.c code from libc without + rewriting it. + (flockfile, ftrylockfile, funlockfile): New macros. + 2003-10-06 Bruno Haible * version-etc-2.h: Remove file. diff --git a/lib/getpass.c b/lib/getpass.c index d2668ec5e9..8a993d3e05 100644 --- a/lib/getpass.c +++ b/lib/getpass.c @@ -19,12 +19,53 @@ # include #endif +#if _LIBC +# define HAVE_STDIO_EXT_H 1 +#endif + +#include + #include +#if HAVE_STDIO_EXT_H +# include +#else +# define __fsetlocking(stream, type) /* empty */ +#endif +#if !_LIBC +# include "getline.h" +#endif + #include #include -#include -#include "getline.h" -#include "unlocked-io.h" + +#if _LIBC +# include +#endif + +#if _LIBC +# define NOTCANCEL_MODE "c" +#else +# define NOTCANCEL_MODE +#endif + +#if _LIBC +# define flockfile(s) _IO_flockfile (s) +# define funlockfile(s) _IO_funlockfile (s) +#else +# include "unlocked-io.h" +#endif + +#if _LIBC +# include +#else +# define __libc_cleanup_push(function, arg) /* empty */ +# define __libc_cleanup_pop(execute) /* empty */ +#endif + +#if !_LIBC +# define __getline getline +# define __tcgetattr tcgetattr +#endif /* It is desirable to use this bit on systems that have it. The only bit of terminal state we want to twiddle is echoing, which is @@ -35,12 +76,20 @@ # define TCSASOFT 0 #endif +static void +call_fclose (void *arg) +{ + if (arg != NULL) + fclose (arg); +} + char * getpass (const char *prompt) { + FILE *tty; FILE *in, *out; struct termios s, t; - int tty_changed; + bool tty_changed; static char *buf; static size_t bufsize; ssize_t nread; @@ -48,18 +97,29 @@ getpass (const char *prompt) /* Try to write to and read from the terminal if we can. If we can't open the terminal, use stderr and stdin. */ - in = fopen ("/dev/tty", "w+"); - if (in == NULL) + tty = fopen ("/dev/tty", "w+" NOTCANCEL_MODE); + if (tty == NULL) { in = stdin; out = stderr; } else - out = in; + { + /* We do the locking ourselves. */ + __fsetlocking (tty, FSETLOCKING_BYCALLER); + + out = in = tty; + } + + /* Make sure the stream we opened is closed even if the thread is + canceled. */ + __libc_cleanup_push (call_fclose, tty); + + flockfile (out); /* Turn echoing off if it is on now. */ - if (tcgetattr (fileno (in), &t) == 0) + if (__tcgetattr (fileno (in), &t) == 0) { /* Save the old one. */ s = t; @@ -68,14 +128,35 @@ getpass (const char *prompt) tty_changed = (tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &t) == 0); } else - tty_changed = 0; + tty_changed = false; /* Write the prompt. */ - fputs (prompt, out); - fflush (out); +#ifdef USE_IN_LIBIO + if (_IO_fwide (out, 0) > 0) + __fwprintf (out, L"%s", prompt); + else +#endif + fputs_unlocked (prompt, out); + fflush_unlocked (out); /* Read the password. */ - nread = getline (&buf, &bufsize, in); + nread = __getline (&buf, &bufsize, in); + +#if !_LIBC + /* As far as is known, glibc doesn't need this no-op fseek. */ + + /* According to the C standard, input may not be followed by output + on the same stream without an intervening call to a file + positioning function. Suppose in == out; then without this fseek + call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets + echoed, whereas on IRIX, the following newline is not output as + it should be. POSIX imposes similar restrictions if fileno (in) + == fileno (out). The POSIX restrictions are tricky and change + from POSIX version to POSIX version, so play it safe and invoke + fseek even if in != out. */ + fseek (out, 0, SEEK_CUR); +#endif + if (buf != NULL) { if (nread < 0) @@ -86,16 +167,13 @@ getpass (const char *prompt) buf[nread - 1] = '\0'; if (tty_changed) { - /* Write the newline that was not echoed. - But before doing that, do a no-op fseek. According to the C - standard, input may not be followed by output on the same - stream without an intervening call to a file positioning - function. Without this fseek() call, on Solaris, HP-UX, - AIX, OSF/1, the previous input gets echoed, whereas on IRIX, - the following newline is not output as it should. */ - if (out == in) - fseek (out, 0, SEEK_CUR); - putc ('\n', out); + /* Write the newline that was not echoed. */ +#ifdef USE_IN_LIBIO + if (_IO_fwide (out, 0) > 0) + putwc_unlocked (L'\n', out); + else +#endif + putc_unlocked ('\n', out); } } } @@ -104,9 +182,11 @@ getpass (const char *prompt) if (tty_changed) (void) tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &s); - if (in != stdin) - /* We opened the terminal; now close it. */ - fclose (in); + funlockfile (out); + + __libc_cleanup_pop (0); + + call_fclose (tty); return buf; } diff --git a/lib/unlocked-io.h b/lib/unlocked-io.h index 3fe5fe105b..4cd7551634 100644 --- a/lib/unlocked-io.h +++ b/lib/unlocked-io.h @@ -27,63 +27,106 @@ # if USE_UNLOCKED_IO -/* These are wrappers for functions/macros from GNU libc. +/* These are wrappers for functions/macros from the GNU C library, and + from other C libraries supporting POSIX's optional thread-safe functions. + The standard I/O functions are thread-safe. These *_unlocked ones are more efficient but not thread-safe. That they're not thread-safe is - fine since all of the applications in this package are single threaded. */ + fine since all of the applications in this package are single threaded. + + Also, some code that is shared with the GNU C library may invoke + the *_unlocked functions directly. On hosts that lack those + functions, invoke the non-thread-safe versions instead. */ + +# include # if HAVE_DECL_CLEARERR_UNLOCKED # undef clearerr # define clearerr(x) clearerr_unlocked (x) +# else +# define clearerr_unlocked(x) clearerr (x) # endif # if HAVE_DECL_FEOF_UNLOCKED # undef feof # define feof(x) feof_unlocked (x) +# else +# define feof_unlocked(x) feof (x) # endif # if HAVE_DECL_FERROR_UNLOCKED # undef ferror # define ferror(x) ferror_unlocked (x) +# else +# define ferror_unlocked(x) ferror (x) # endif # if HAVE_DECL_FFLUSH_UNLOCKED # undef fflush # define fflush(x) fflush_unlocked (x) +# else +# define fflush_unlocked(x) fflush (x) # endif # if HAVE_DECL_FGETS_UNLOCKED # undef fgets # define fgets(x,y,z) fgets_unlocked (x,y,z) +# else +# define fgets_unlocked(x,y,z) fgets (x,y,z) # endif # if HAVE_DECL_FPUTC_UNLOCKED # undef fputc # define fputc(x,y) fputc_unlocked (x,y) +# else +# define fputc_unlocked(x,y) fputc (x,y) # endif # if HAVE_DECL_FPUTS_UNLOCKED # undef fputs # define fputs(x,y) fputs_unlocked (x,y) +# else +# define fputs_unlocked(x,y) fputs (x,y) # endif # if HAVE_DECL_FREAD_UNLOCKED # undef fread # define fread(w,x,y,z) fread_unlocked (w,x,y,z) +# else +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) # endif # if HAVE_DECL_FWRITE_UNLOCKED # undef fwrite # define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z) +# else +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) # endif # if HAVE_DECL_GETC_UNLOCKED # undef getc # define getc(x) getc_unlocked (x) +# else +# define getc_unlocked(x) getc (x) # endif # if HAVE_DECL_GETCHAR_UNLOCKED # undef getchar # define getchar() getchar_unlocked () +# else +# define getchar_unlocked() getchar () # endif # if HAVE_DECL_PUTC_UNLOCKED # undef putc # define putc(x,y) putc_unlocked (x,y) +# else +# define putc_unlocked(x,y) putc (x,y) # endif # if HAVE_DECL_PUTCHAR_UNLOCKED # undef putchar # define putchar(x) putchar_unlocked (x) +# else +# define putchar_unlocked(x) putchar (x) # endif +# undef flockfile +# define flockfile(x) ((void) 0) + +# undef ftrylockfile +# define ftrylockfile(x) 0 + +# undef funlockfile +# define funlockfile(x) ((void) 0) + # endif /* USE_UNLOCKED_IO */ #endif /* UNLOCKED_IO_H */ diff --git a/m4/ChangeLog b/m4/ChangeLog index 63e9433382..5efda7cd19 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,7 @@ +2003-10-08 Paul Eggert + + * getpass.m4 (gl_PREREQ_GETPASS): Check for stdio_ext.h. + 2003-10-06 Bruno Haible * fatal-signal.m4: New file. diff --git a/m4/getpass.m4 b/m4/getpass.m4 index 0a7b817421..29c9d6eefd 100644 --- a/m4/getpass.m4 +++ b/m4/getpass.m4 @@ -1,4 +1,4 @@ -# getpass.m4 serial 2 +# getpass.m4 serial 3 dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General @@ -31,6 +31,7 @@ AC_DEFUN([gl_FUNC_GETPASS_GNU], # Prerequisites of lib/getpass.c. AC_DEFUN([gl_PREREQ_GETPASS], [ + AC_CHECK_HEADERS_ONCE(stdio_ext.h) : ]) diff --git a/modules/getpass b/modules/getpass index fb5aa9d7b3..f7d00f31c6 100644 --- a/modules/getpass +++ b/modules/getpass @@ -8,6 +8,7 @@ m4/getpass.m4 Depends-on: unlocked-io getline +stdbool configure.ac: gl_FUNC_GETPASS