bb_askpass: handle Ctrl-C, restore termoios on Ctrl-C.
[people/mcb30/busybox.git] / libbb / bb_askpass.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Ask for a password
4  * I use a static buffer in this function.  Plan accordingly.
5  *
6  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7  *
8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9  */
10
11 #include <termios.h>
12
13 #include "libbb.h"
14
15 /* do nothing signal handler */
16 static void askpass_timeout(int ATTRIBUTE_UNUSED ignore)
17 {
18 }
19
20 char *bb_askpass(int timeout, const char *prompt)
21 {
22         /* Was static char[BIGNUM] */
23         enum { sizeof_passwd = 128 };
24         static char *passwd;
25
26         char *ret;
27         int i;
28         struct sigaction sa, oldsa;
29         struct termios tio, oldtio;
30
31         if (!passwd)
32                 passwd = xmalloc(sizeof_passwd);
33         memset(passwd, 0, sizeof_passwd);
34
35         tcgetattr(STDIN_FILENO, &oldtio);
36         tcflush(STDIN_FILENO, TCIFLUSH);
37         tio = oldtio;
38         tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
39         tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
40         tcsetattr(STDIN_FILENO, TCSANOW, &tio);
41
42         memset(&sa, 0, sizeof(sa));
43         /* sa.sa_flags = 0; - no SA_RESTART! */
44         /* SIGINT and SIGALRM will interrupt read below */
45         sa.sa_handler = askpass_timeout;
46         sigaction(SIGINT, &sa, &oldsa);
47         if (timeout) {
48                 sigaction(SIGALRM, &sa, NULL);
49                 alarm(timeout);
50         }
51
52         fputs(prompt, stdout);
53         fflush(stdout);
54         ret = NULL;
55         /* On timeout or Ctrl-C, read will hopefully be interrupted,
56          * and we return NULL */
57         if (read(STDIN_FILENO, passwd, sizeof_passwd - 1) > 0) {
58                 ret = passwd;
59                 i = 0;
60                 /* Last byte is guaranteed to be 0
61                    (read did not overwrite it) */
62                 do {
63                         if (passwd[i] == '\r' || passwd[i] == '\n')
64                                 passwd[i] = '\0';
65                 } while (passwd[i++]);
66         }
67
68         if (timeout) {
69                 alarm(0);
70         }
71         sigaction(SIGINT, &oldsa, NULL);
72
73         tcsetattr(STDIN_FILENO, TCSANOW, &oldtio);
74         bb_putchar('\n');
75         fflush(stdout);
76         return ret;
77 }