utf8proc: Update from 2.1.0 to 2.1.1
[termux-packages] / packages / alpine / getpass.c
CommitLineData
d628b9b0 1/* Copyright (C) 1992-2001, 2003-2007, 2009-2016 Free Software Foundation, Inc.
2
3 This file is part of the GNU C Library.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, see <http://www.gnu.org/licenses/>. */
17
18/*#ifndef _LIBC
19# include <config.h>
20#endifi*/
21
22#include "getpass.h"
23
24
25#include <stdio.h>
26
27#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
28
29# include <stdbool.h>
30
31# if HAVE_DECL___FSETLOCKING && HAVE___FSETLOCKING
32# if HAVE_STDIO_EXT_H
33# include <stdio_ext.h>
34# endif
35# else
36# define __fsetlocking(stream, type) /* empty */
37# endif
38
39# if HAVE_TERMIOS_H
40# include <termios.h>
41# endif
42
43# if USE_UNLOCKED_IO
44# include "unlocked-io.h"
45# else
46# if !HAVE_DECL_FFLUSH_UNLOCKED
47# undef fflush_unlocked
48# define fflush_unlocked(x) fflush (x)
49# endif
50# if !HAVE_DECL_FLOCKFILE
51# undef flockfile
52# define flockfile(x) ((void) 0)
53# endif
54# if !HAVE_DECL_FUNLOCKFILE
55# undef funlockfile
56# define funlockfile(x) ((void) 0)
57# endif
58# if !HAVE_DECL_FPUTS_UNLOCKED
59# undef fputs_unlocked
60# define fputs_unlocked(str,stream) fputs (str, stream)
61# endif
62# if !HAVE_DECL_PUTC_UNLOCKED
63# undef putc_unlocked
64# define putc_unlocked(c,stream) putc (c, stream)
65# endif
66# endif
67
68/* It is desirable to use this bit on systems that have it.
69 The only bit of terminal state we want to twiddle is echoing, which is
70 done in software; there is no need to change the state of the terminal
71 hardware. */
72
73# ifndef TCSASOFT
74# define TCSASOFT 0
75# endif
76
77static void
78call_fclose (void *arg)
79{
80 if (arg != NULL)
81 fclose (arg);
82}
83
84char *
85getpass (const char *prompt)
86{
87 FILE *tty;
88 FILE *in, *out;
89# if HAVE_TCGETATTR
90 struct termios s, t;
91# endif
92 bool tty_changed = false;
93 static char *buf;
94 static size_t bufsize;
95 ssize_t nread;
96
97 /* Try to write to and read from the terminal if we can.
98 If we can't open the terminal, use stderr and stdin. */
99
100 tty = fopen ("/dev/tty", "w+");
101 if (tty == NULL)
102 {
103 in = stdin;
104 out = stderr;
105 }
106 else
107 {
108 /* We do the locking ourselves. */
109 __fsetlocking (tty, FSETLOCKING_BYCALLER);
110
111 out = in = tty;
112 }
113
114 flockfile (out);
115
116 /* Turn echoing off if it is on now. */
117# if HAVE_TCGETATTR
118 if (tcgetattr (fileno (in), &t) == 0)
119 {
120 /* Save the old one. */
121 s = t;
122 /* Tricky, tricky. */
123 t.c_lflag &= ~(ECHO | ISIG);
124 tty_changed = (tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &t) == 0);
125 }
126# endif
127
128 /* Write the prompt. */
129 fputs_unlocked (prompt, out);
130 fflush_unlocked (out);
131
132 /* Read the password. */
133 nread = getline (&buf, &bufsize, in);
134
135 /* According to the C standard, input may not be followed by output
136 on the same stream without an intervening call to a file
137 positioning function. Suppose in == out; then without this fseek
138 call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
139 echoed, whereas on IRIX, the following newline is not output as
140 it should be. POSIX imposes similar restrictions if fileno (in)
141 == fileno (out). The POSIX restrictions are tricky and change
142 from POSIX version to POSIX version, so play it safe and invoke
143 fseek even if in != out. */
144 fseeko (out, 0, SEEK_CUR);
145
146 if (buf != NULL)
147 {
148 if (nread < 0)
149 buf[0] = '\0';
150 else if (buf[nread - 1] == '\n')
151 {
152 /* Remove the newline. */
153 buf[nread - 1] = '\0';
154 if (tty_changed)
155 {
156 /* Write the newline that was not echoed. */
157 putc_unlocked ('\n', out);
158 }
159 }
160 }
161
162 /* Restore the original setting. */
163# if HAVE_TCSETATTR
164 if (tty_changed)
165 tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &s);
166# endif
167
168 funlockfile (out);
169
170 call_fclose (tty);
171
172 return buf;
173}
174
175#else /* W32 native */
176
177/* Windows implementation by Martin Lambers <marlam@marlam.de>,
178 improved by Simon Josefsson. */
179
180/* For PASS_MAX. */
181# include <limits.h>
182/* For _getch(). */
183# include <conio.h>
184/* For strdup(). */
185# include <string.h>
186
187# ifndef PASS_MAX
188# define PASS_MAX 512
189# endif
190
191char *
192getpass (const char *prompt)
193{
194 char getpassbuf[PASS_MAX + 1];
195 size_t i = 0;
196 int c;
197
198 if (prompt)
199 {
200 fputs (prompt, stderr);
201 fflush (stderr);
202 }
203
204 for (;;)
205 {
206 c = _getch ();
207 if (c == '\r')
208 {
209 getpassbuf[i] = '\0';
210 break;
211 }
212 else if (i < PASS_MAX)
213 {
214 getpassbuf[i++] = c;
215 }
216
217 if (i >= PASS_MAX)
218 {
219 getpassbuf[i] = '\0';
220 break;
221 }
222 }
223
224 if (prompt)
225 {
226 fputs ("\r\n", stderr);
227 fflush (stderr);
228 }
229
230 return strdup (getpassbuf);
231}
232#endif