xref: /freebsd/crypto/krb5/src/util/ss/listen.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* util/ss/listen.c */
3 /*
4  * Copyright 1987, 1988 by MIT Student Information Processing Board
5  *
6  * For copyright information, see copyright.h.
7  */
8 
9 #include "copyright.h"
10 #include "ss_internal.h"
11 #include <stdio.h>
12 #include <setjmp.h>
13 #include <signal.h>
14 #include <termios.h>
15 #include <sys/param.h>
16 
17 #if defined(HAVE_LIBEDIT)
18 #include <editline/readline.h>
19 #elif defined(HAVE_READLINE)
20 #include <readline/readline.h>
21 #include <readline/history.h>
22 #else
23 #define NO_READLINE
24 #endif
25 
26 static ss_data *current_info;
27 static jmp_buf listen_jmpb;
28 
29 #ifdef NO_READLINE
30 /* Dumb replacement for readline when we don't have support for a real one. */
31 static char *
readline(const char * prompt)32 readline(const char *prompt)
33 {
34     struct termios termbuf;
35     char input[BUFSIZ];
36 
37     /* Make sure we don't buffer anything beyond the line read. */
38     setvbuf(stdin, 0, _IONBF, 0);
39 
40     if (tcgetattr(STDIN_FILENO, &termbuf) == 0) {
41         termbuf.c_lflag |= ICANON|ISIG|ECHO;
42         tcsetattr(STDIN_FILENO, TCSANOW, &termbuf);
43     }
44     printf("%s", prompt);
45     fflush(stdout);
46     if (fgets(input, BUFSIZ, stdin) == NULL)
47         return NULL;
48     input[strcspn(input, "\r\n")] = '\0';
49     return strdup(input);
50 }
51 
52 /* No-op replacement for add_history() when we have no readline support. */
53 static void
add_history(const char * line)54 add_history(const char *line)
55 {
56 }
57 #endif
58 
59 static void
listen_int_handler(int signo)60 listen_int_handler(int signo)
61 {
62     putc('\n', stdout);
63     longjmp(listen_jmpb, 1);
64 }
65 
66 int
ss_listen(int sci_idx)67 ss_listen(int sci_idx)
68 {
69     char *cp;
70     ss_data *info;
71     char *input;
72     int code;
73     jmp_buf old_jmpb;
74     ss_data *old_info = current_info;
75 #ifdef POSIX_SIGNALS
76     struct sigaction isig, csig, nsig, osig;
77     sigset_t nmask, omask;
78 #else
79     void (*sig_cont)();
80     void (*sig_int)(), (*old_sig_cont)();
81     int mask;
82 #endif
83 
84     current_info = info = ss_info(sci_idx);
85     info->abort = 0;
86 
87 #ifdef POSIX_SIGNALS
88     csig.sa_handler = (void (*)(int))0;
89     sigemptyset(&nmask);
90     sigaddset(&nmask, SIGINT);
91     sigprocmask(SIG_BLOCK, &nmask, &omask);
92 #else
93     sig_cont = (void (*)(int))0;
94     mask = sigblock(sigmask(SIGINT));
95 #endif
96 
97     memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
98 
99 #ifdef POSIX_SIGNALS
100     nsig.sa_handler = listen_int_handler;
101     sigemptyset(&nsig.sa_mask);
102     nsig.sa_flags = 0;
103     sigaction(SIGINT, &nsig, &isig);
104 #else
105     sig_int = signal(SIGINT, listen_int_handler);
106 #endif
107 
108     setjmp(listen_jmpb);
109 
110 #ifdef POSIX_SIGNALS
111     sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
112 #else
113     (void) sigsetmask(mask);
114 #endif
115     while(!info->abort) {
116 #ifdef POSIX_SIGNALS
117         nsig.sa_handler = listen_int_handler;   /* fgets is not signal-safe */
118         osig = csig;
119         sigaction(SIGCONT, &nsig, &csig);
120         if ((void (*)(int))csig.sa_handler==(void (*)(int))listen_int_handler)
121             csig = osig;
122 #else
123         old_sig_cont = sig_cont;
124         sig_cont = signal(SIGCONT, listen_int_handler);
125         if (sig_cont == listen_int_handler)
126             sig_cont = old_sig_cont;
127 #endif
128 
129         input = readline(current_info->prompt);
130         if (input == NULL) {
131             code = SS_ET_EOF;
132             goto egress;
133         }
134         add_history(input);
135 
136 #ifdef POSIX_SIGNALS
137         sigaction(SIGCONT, &csig, (struct sigaction *)0);
138 #else
139         (void) signal(SIGCONT, sig_cont);
140 #endif
141 
142         code = ss_execute_line (sci_idx, input);
143         if (code == SS_ET_COMMAND_NOT_FOUND) {
144             char *c = input;
145             while (*c == ' ' || *c == '\t')
146                 c++;
147             cp = strchr (c, ' ');
148             if (cp)
149                 *cp = '\0';
150             cp = strchr (c, '\t');
151             if (cp)
152                 *cp = '\0';
153             ss_error (sci_idx, 0,
154                       "Unknown request \"%s\".  Type \"?\" for a request list.",
155                       c);
156         }
157         free(input);
158     }
159     code = 0;
160 egress:
161 #ifdef POSIX_SIGNALS
162     sigaction(SIGINT, &isig, (struct sigaction *)0);
163 #else
164     (void) signal(SIGINT, sig_int);
165 #endif
166     memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
167     current_info = old_info;
168     return code;
169 }
170 
171 void
ss_abort_subsystem(int sci_idx,int code)172 ss_abort_subsystem(int sci_idx, int code)
173 {
174     ss_info(sci_idx)->abort = 1;
175     ss_info(sci_idx)->exit_status = code;
176 
177 }
178 
179 void
ss_quit(int argc,char const * const * argv,int sci_idx,pointer infop)180 ss_quit(int argc, char const * const *argv, int sci_idx, pointer infop)
181 {
182     ss_abort_subsystem(sci_idx, 0);
183 }
184