9aecad68a04817efc4410846a8bcb58c262765d4
   1#include "git-compat-util.h"
   2#include "compat/terminal.h"
   3#include "sigchain.h"
   4#include "strbuf.h"
   5
   6#ifdef HAVE_DEV_TTY
   7
   8static int term_fd = -1;
   9static struct termios old_term;
  10
  11static void restore_term(void)
  12{
  13        if (term_fd < 0)
  14                return;
  15
  16        tcsetattr(term_fd, TCSAFLUSH, &old_term);
  17        close(term_fd);
  18        term_fd = -1;
  19}
  20
  21static void restore_term_on_signal(int sig)
  22{
  23        restore_term();
  24        sigchain_pop(sig);
  25        raise(sig);
  26}
  27
  28static int disable_echo(void)
  29{
  30        struct termios t;
  31
  32        term_fd = open("/dev/tty", O_RDWR);
  33        if (tcgetattr(term_fd, &t) < 0)
  34                goto error;
  35
  36        old_term = t;
  37        sigchain_push_common(restore_term_on_signal);
  38
  39        t.c_lflag &= ~ECHO;
  40        if (!tcsetattr(term_fd, TCSAFLUSH, &t))
  41                return 0;
  42
  43error:
  44        close(term_fd);
  45        term_fd = -1;
  46        return -1;
  47}
  48
  49char *git_terminal_prompt(const char *prompt, int echo)
  50{
  51        static struct strbuf buf = STRBUF_INIT;
  52        int r;
  53        FILE *input_fh, *output_fh;
  54
  55        input_fh = fopen("/dev/tty", "r");
  56        if (!input_fh)
  57                return NULL;
  58
  59        output_fh = fopen("/dev/tty", "w");
  60        if (!output_fh) {
  61                fclose(input_fh);
  62                return NULL;
  63        }
  64
  65        if (!echo && disable_echo()) {
  66                fclose(input_fh);
  67                fclose(output_fh);
  68                return NULL;
  69        }
  70
  71        fputs(prompt, output_fh);
  72        fflush(output_fh);
  73
  74        r = strbuf_getline(&buf, input_fh, '\n');
  75        if (!echo) {
  76                putc('\n', output_fh);
  77                fflush(output_fh);
  78        }
  79
  80        restore_term();
  81        fclose(input_fh);
  82        fclose(output_fh);
  83
  84        if (r == EOF)
  85                return NULL;
  86        return buf.buf;
  87}
  88
  89#else
  90
  91char *git_terminal_prompt(const char *prompt, int echo)
  92{
  93        return getpass(prompt);
  94}
  95
  96#endif