Import (slightly modified) ru.koi8-r.win.kbd:1.1 from FreeBSD (fjoe):
[dragonfly.git] / contrib / cvs-1.12.11 / lib / getpass.c
1 /* Copyright (C) 1992-2001, 2003, 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #if !_LIBC
23 # include "getpass.h"
24 #endif
25
26 #if _LIBC
27 # define HAVE_STDIO_EXT_H 1
28 #endif
29
30 #include <stdbool.h>
31
32 #include <stdio.h>
33 #if HAVE_STDIO_EXT_H
34 # include <stdio_ext.h>
35 #else
36 # define __fsetlocking(stream, type) /* empty */
37 #endif
38 #if !_LIBC
39 # include "getline.h"
40 #endif
41
42 #include <termios.h>
43 #include <unistd.h>
44
45 #if _LIBC
46 # include <wchar.h>
47 #endif
48
49 #if _LIBC
50 # define NOTCANCEL_MODE "c"
51 #else
52 # define NOTCANCEL_MODE
53 #endif
54
55 #if _LIBC
56 # define flockfile(s) _IO_flockfile (s)
57 # define funlockfile(s) _IO_funlockfile (s)
58 #elif USE_UNLOCKED_IO
59 # include "unlocked-io.h"
60 #else
61 # if !HAVE_DECL_FFLUSH_UNLOCKED
62 #  undef fflush_unlocked
63 #  define fflush_unlocked(x) fflush (x)
64 # endif
65 # if !HAVE_DECL_FLOCKFILE
66 #  undef flockfile
67 #  define flockfile(x) ((void) 0)
68 # endif
69 # if !HAVE_DECL_FUNLOCKFILE
70 #  undef funlockfile
71 #  define funlockfile(x) ((void) 0)
72 # endif
73 # if !HAVE_DECL_FPUTS_UNLOCKED
74 #  undef fputs_unlocked
75 #  define fputs_unlocked(str,stream) fputs (str, stream)
76 # endif
77 # if !HAVE_DECL_PUTC_UNLOCKED
78 #  undef putc_unlocked
79 #  define putc_unlocked(c,stream) putc (c, stream)
80 # endif
81 #endif
82
83 #if _LIBC
84 # include <bits/libc-lock.h>
85 #else
86 # define __libc_cleanup_push(function, arg) /* empty */
87 # define __libc_cleanup_pop(execute) /* empty */
88 #endif
89
90 #if !_LIBC
91 # define __getline getline
92 # define __tcgetattr tcgetattr
93 #endif
94
95 /* It is desirable to use this bit on systems that have it.
96    The only bit of terminal state we want to twiddle is echoing, which is
97    done in software; there is no need to change the state of the terminal
98    hardware.  */
99
100 #ifndef TCSASOFT
101 # define TCSASOFT 0
102 #endif
103
104 static void
105 call_fclose (void *arg)
106 {
107   if (arg != NULL)
108     fclose (arg);
109 }
110
111 char *
112 getpass (const char *prompt)
113 {
114   FILE *tty;
115   FILE *in, *out;
116   struct termios s, t;
117   bool tty_changed;
118   static char *buf;
119   static size_t bufsize;
120   ssize_t nread;
121
122   /* Try to write to and read from the terminal if we can.
123      If we can't open the terminal, use stderr and stdin.  */
124
125   tty = fopen ("/dev/tty", "w+" NOTCANCEL_MODE);
126   if (tty == NULL)
127     {
128       in = stdin;
129       out = stderr;
130     }
131   else
132     {
133       /* We do the locking ourselves.  */
134       __fsetlocking (tty, FSETLOCKING_BYCALLER);
135
136       out = in = tty;
137     }
138
139   /* Make sure the stream we opened is closed even if the thread is
140      canceled.  */
141   __libc_cleanup_push (call_fclose, tty);
142
143   flockfile (out);
144
145   /* Turn echoing off if it is on now.  */
146
147   if (__tcgetattr (fileno (in), &t) == 0)
148     {
149       /* Save the old one. */
150       s = t;
151       /* Tricky, tricky. */
152       t.c_lflag &= ~(ECHO|ISIG);
153       tty_changed = (tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &t) == 0);
154     }
155   else
156     tty_changed = false;
157
158   /* Write the prompt.  */
159 #ifdef USE_IN_LIBIO
160   if (_IO_fwide (out, 0) > 0)
161     __fwprintf (out, L"%s", prompt);
162   else
163 #endif
164     fputs_unlocked (prompt, out);
165   fflush_unlocked (out);
166
167   /* Read the password.  */
168   nread = __getline (&buf, &bufsize, in);
169
170 #if !_LIBC
171   /* As far as is known, glibc doesn't need this no-op fseek.  */
172
173   /* According to the C standard, input may not be followed by output
174      on the same stream without an intervening call to a file
175      positioning function.  Suppose in == out; then without this fseek
176      call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
177      echoed, whereas on IRIX, the following newline is not output as
178      it should be.  POSIX imposes similar restrictions if fileno (in)
179      == fileno (out).  The POSIX restrictions are tricky and change
180      from POSIX version to POSIX version, so play it safe and invoke
181      fseek even if in != out.  */
182   fseek (out, 0, SEEK_CUR);
183 #endif
184
185   if (buf != NULL)
186     {
187       if (nread < 0)
188         buf[0] = '\0';
189       else if (buf[nread - 1] == '\n')
190         {
191           /* Remove the newline.  */
192           buf[nread - 1] = '\0';
193           if (tty_changed)
194             {
195               /* Write the newline that was not echoed.  */
196 #ifdef USE_IN_LIBIO
197               if (_IO_fwide (out, 0) > 0)
198                 putwc_unlocked (L'\n', out);
199               else
200 #endif
201                 putc_unlocked ('\n', out);
202             }
203         }
204     }
205
206   /* Restore the original setting.  */
207   if (tty_changed)
208     (void) tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &s);
209
210   funlockfile (out);
211
212   __libc_cleanup_pop (0);
213
214   call_fclose (tty);
215
216   return buf;
217 }