xref: /aosp_15_r20/external/mtools/tty.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1*d5c9a868SElliott Hughes /*  Copyright 1997,2001,2002,2007-2009 Alain Knaff.
2*d5c9a868SElliott Hughes  *  This file is part of mtools.
3*d5c9a868SElliott Hughes  *
4*d5c9a868SElliott Hughes  *  Mtools is free software: you can redistribute it and/or modify
5*d5c9a868SElliott Hughes  *  it under the terms of the GNU General Public License as published by
6*d5c9a868SElliott Hughes  *  the Free Software Foundation, either version 3 of the License, or
7*d5c9a868SElliott Hughes  *  (at your option) any later version.
8*d5c9a868SElliott Hughes  *
9*d5c9a868SElliott Hughes  *  Mtools is distributed in the hope that it will be useful,
10*d5c9a868SElliott Hughes  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11*d5c9a868SElliott Hughes  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*d5c9a868SElliott Hughes  *  GNU General Public License for more details.
13*d5c9a868SElliott Hughes  *
14*d5c9a868SElliott Hughes  *  You should have received a copy of the GNU General Public License
15*d5c9a868SElliott Hughes  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16*d5c9a868SElliott Hughes  */
17*d5c9a868SElliott Hughes 
18*d5c9a868SElliott Hughes #include "sysincludes.h"
19*d5c9a868SElliott Hughes #include "mtools.h"
20*d5c9a868SElliott Hughes 
21*d5c9a868SElliott Hughes static FILE *tty=NULL;
22*d5c9a868SElliott Hughes static int notty=0;
23*d5c9a868SElliott Hughes static int ttyfd=-1;
24*d5c9a868SElliott Hughes #ifdef USE_RAWTERM
25*d5c9a868SElliott Hughes int	mtools_raw_tty = 1;
26*d5c9a868SElliott Hughes #else
27*d5c9a868SElliott Hughes int	mtools_raw_tty = 0;
28*d5c9a868SElliott Hughes #endif
29*d5c9a868SElliott Hughes 
30*d5c9a868SElliott Hughes #ifdef USE_RAWTERM
31*d5c9a868SElliott Hughes # if defined TCSANOW && defined HAVE_TCSETATTR
32*d5c9a868SElliott Hughes /* we have tcsetattr & tcgetattr. Good */
33*d5c9a868SElliott Hughes typedef struct termios Terminal;
34*d5c9a868SElliott Hughes #  define stty(a,b)        (void)tcsetattr(a,TCSANOW,b)
35*d5c9a868SElliott Hughes #  define gtty(a,b)        (void)tcgetattr(a,b)
36*d5c9a868SElliott Hughes #  define USE_TCIFLUSH
37*d5c9a868SElliott Hughes 
38*d5c9a868SElliott Hughes # elif defined TCSETS && defined TCGETS
39*d5c9a868SElliott Hughes typedef struct termios Terminal;
40*d5c9a868SElliott Hughes #  define stty(a,b) (void)ioctl(a,TCSETS,(char *)b)
41*d5c9a868SElliott Hughes #  define gtty(a,b) (void)ioctl(a,TCGETS,(char *)b)
42*d5c9a868SElliott Hughes #  define USE_TCIFLUSH
43*d5c9a868SElliott Hughes 
44*d5c9a868SElliott Hughes # elif defined TCSETA && defined TCGETA
45*d5c9a868SElliott Hughes typedef struct termio Terminal;
46*d5c9a868SElliott Hughes #  define stty(a,b) (void)ioctl(a,TCSETA,(char *)b)
47*d5c9a868SElliott Hughes #  define gtty(a,b) (void)ioctl(a,TCGETA,(char *)b)
48*d5c9a868SElliott Hughes #  define USE_TCIFLUSH
49*d5c9a868SElliott Hughes 
50*d5c9a868SElliott Hughes # elif defined(HAVE_SGTTY_H) && defined(TIOCSETP) && defined(TIOCGETP)
51*d5c9a868SElliott Hughes typedef struct sgttyb Terminal;
52*d5c9a868SElliott Hughes #  define stty(a,b) (void)ioctl(a,TIOCSETP,(char *)b)
53*d5c9a868SElliott Hughes #  define gtty(a,b) (void)ioctl(a,TIOCGETP,(char *)b)
54*d5c9a868SElliott Hughes #  define USE_SGTTY
55*d5c9a868SElliott Hughes #  define discard_input(a) /**/
56*d5c9a868SElliott Hughes 
57*d5c9a868SElliott Hughes # else
58*d5c9a868SElliott Hughes /* no way to use raw terminal */
59*d5c9a868SElliott Hughes #  warning Cannot use raw terminal code (disabled)
60*d5c9a868SElliott Hughes #  undef USE_RAWTERM
61*d5c9a868SElliott Hughes # endif
62*d5c9a868SElliott Hughes 
63*d5c9a868SElliott Hughes #endif
64*d5c9a868SElliott Hughes 
65*d5c9a868SElliott Hughes #ifdef USE_TCIFLUSH
66*d5c9a868SElliott Hughes # if defined TCIFLUSH && defined HAVE_TCFLUSH
67*d5c9a868SElliott Hughes #  define discard_input(a) tcflush(a,TCIFLUSH)
68*d5c9a868SElliott Hughes # else
69*d5c9a868SElliott Hughes #  define discard_input(a) /**/
70*d5c9a868SElliott Hughes # endif
71*d5c9a868SElliott Hughes #endif
72*d5c9a868SElliott Hughes 
73*d5c9a868SElliott Hughes #ifdef USE_RAWTERM
74*d5c9a868SElliott Hughes 
75*d5c9a868SElliott Hughes static int tty_mode = -1; /* 1 for raw, 0 for cooked, -1 for initial */
76*d5c9a868SElliott Hughes static int need_tty_reset = 0;
77*d5c9a868SElliott Hughes static int handlerIsSet = 0;
78*d5c9a868SElliott Hughes 
79*d5c9a868SElliott Hughes #define restore_tty(a) stty(STDIN,a)
80*d5c9a868SElliott Hughes 
81*d5c9a868SElliott Hughes 
82*d5c9a868SElliott Hughes #define STDIN ttyfd
83*d5c9a868SElliott Hughes #ifdef future
84*d5c9a868SElliott Hughes #define FAIL (-1)
85*d5c9a868SElliott Hughes #endif
86*d5c9a868SElliott Hughes #define DONE 0
87*d5c9a868SElliott Hughes static Terminal in_orig;
88*d5c9a868SElliott Hughes 
89*d5c9a868SElliott Hughes /*--------------- Signal Handler routines -------------*/
90*d5c9a868SElliott Hughes 
91*d5c9a868SElliott Hughes static void tty_time_out(int dummy UNUSEDP) NORETURN;
tty_time_out(int dummy UNUSEDP)92*d5c9a868SElliott Hughes static void tty_time_out(int dummy UNUSEDP)
93*d5c9a868SElliott Hughes {
94*d5c9a868SElliott Hughes 	int exit_code;
95*d5c9a868SElliott Hughes 	signal(SIGALRM, SIG_IGN);
96*d5c9a868SElliott Hughes 	if(tty && need_tty_reset)
97*d5c9a868SElliott Hughes 		restore_tty (&in_orig);
98*d5c9a868SElliott Hughes #ifdef future
99*d5c9a868SElliott Hughes 	if (fail_on_timeout)
100*d5c9a868SElliott Hughes 		exit_code=SHFAIL;
101*d5c9a868SElliott Hughes 	else {
102*d5c9a868SElliott Hughes 		if (default_choice && mode_defined) {
103*d5c9a868SElliott Hughes 			if (yes_no) {
104*d5c9a868SElliott Hughes 				if ('Y' == default_choice)
105*d5c9a868SElliott Hughes 					exit_code=0;
106*d5c9a868SElliott Hughes 				else
107*d5c9a868SElliott Hughes 					exit_code=1;
108*d5c9a868SElliott Hughes 			} else
109*d5c9a868SElliott Hughes 				exit_code=default_choice-minc+1;
110*d5c9a868SElliott Hughes 		} else
111*d5c9a868SElliott Hughes 			exit_code=DONE;
112*d5c9a868SElliott Hughes 	}
113*d5c9a868SElliott Hughes #else
114*d5c9a868SElliott Hughes 	exit_code = DONE;
115*d5c9a868SElliott Hughes #endif
116*d5c9a868SElliott Hughes 	exit(exit_code);
117*d5c9a868SElliott Hughes }
118*d5c9a868SElliott Hughes 
cleanup_tty(void)119*d5c9a868SElliott Hughes static void cleanup_tty(void)
120*d5c9a868SElliott Hughes {
121*d5c9a868SElliott Hughes 	if(tty && need_tty_reset) {
122*d5c9a868SElliott Hughes 		restore_tty (&in_orig);
123*d5c9a868SElliott Hughes 		setup_signal();
124*d5c9a868SElliott Hughes 	}
125*d5c9a868SElliott Hughes }
126*d5c9a868SElliott Hughes 
set_raw_tty(int mode)127*d5c9a868SElliott Hughes static void set_raw_tty(int mode)
128*d5c9a868SElliott Hughes {
129*d5c9a868SElliott Hughes 	Terminal in_raw;
130*d5c9a868SElliott Hughes 
131*d5c9a868SElliott Hughes 	if(mode != tty_mode && mode != -1) {
132*d5c9a868SElliott Hughes 		if(!handlerIsSet) {
133*d5c9a868SElliott Hughes 			/* Determine existing TTY settings */
134*d5c9a868SElliott Hughes 			gtty (STDIN, &in_orig);
135*d5c9a868SElliott Hughes 			need_tty_reset = 1;
136*d5c9a868SElliott Hughes 
137*d5c9a868SElliott Hughes 			/* Restore original TTY settings on exit */
138*d5c9a868SElliott Hughes 			atexit(cleanup_tty);
139*d5c9a868SElliott Hughes 			handlerIsSet = 1;
140*d5c9a868SElliott Hughes 		}
141*d5c9a868SElliott Hughes 
142*d5c9a868SElliott Hughes 
143*d5c9a868SElliott Hughes 		setup_signal();
144*d5c9a868SElliott Hughes 		signal (SIGALRM, tty_time_out);
145*d5c9a868SElliott Hughes 
146*d5c9a868SElliott Hughes 		/* Change STDIN settings to raw */
147*d5c9a868SElliott Hughes 
148*d5c9a868SElliott Hughes 		gtty (STDIN, &in_raw);
149*d5c9a868SElliott Hughes 		if(mode) {
150*d5c9a868SElliott Hughes #ifdef USE_SGTTY
151*d5c9a868SElliott Hughes 			in_raw.sg_flags |= CBREAK;
152*d5c9a868SElliott Hughes #else
153*d5c9a868SElliott Hughes 			in_raw.c_lflag &= ~0u ^ ICANON;
154*d5c9a868SElliott Hughes 			in_raw.c_cc[VMIN]=1;
155*d5c9a868SElliott Hughes 			in_raw.c_cc[VTIME]=0;
156*d5c9a868SElliott Hughes #endif
157*d5c9a868SElliott Hughes 			stty (STDIN, &in_raw);
158*d5c9a868SElliott Hughes 		} else {
159*d5c9a868SElliott Hughes #ifdef USE_SGTTY
160*d5c9a868SElliott Hughes 			in_raw.sg_flags &= ~CBREAK;
161*d5c9a868SElliott Hughes #else
162*d5c9a868SElliott Hughes 			in_raw.c_lflag |= ICANON;
163*d5c9a868SElliott Hughes #endif
164*d5c9a868SElliott Hughes 			stty (STDIN, &in_raw);
165*d5c9a868SElliott Hughes 		}
166*d5c9a868SElliott Hughes 		tty_mode = mode;
167*d5c9a868SElliott Hughes 		discard_input(STDIN);
168*d5c9a868SElliott Hughes 	}
169*d5c9a868SElliott Hughes }
170*d5c9a868SElliott Hughes #endif
171*d5c9a868SElliott Hughes 
opentty(int mode UNUSEDP)172*d5c9a868SElliott Hughes FILE *opentty(int mode UNUSEDP)
173*d5c9a868SElliott Hughes {
174*d5c9a868SElliott Hughes 	if(notty)
175*d5c9a868SElliott Hughes 		return NULL;
176*d5c9a868SElliott Hughes 	if (tty == NULL) {
177*d5c9a868SElliott Hughes 		ttyfd = open("/dev/tty", O_RDONLY);
178*d5c9a868SElliott Hughes 		if(ttyfd >= 0) {
179*d5c9a868SElliott Hughes 			tty = fdopen(ttyfd, "r");
180*d5c9a868SElliott Hughes 		}
181*d5c9a868SElliott Hughes 	}
182*d5c9a868SElliott Hughes 	if  (tty == NULL){
183*d5c9a868SElliott Hughes 		if ( !isatty(0) ){
184*d5c9a868SElliott Hughes 			notty = 1;
185*d5c9a868SElliott Hughes 			return NULL;
186*d5c9a868SElliott Hughes 		}
187*d5c9a868SElliott Hughes 		ttyfd = 0;
188*d5c9a868SElliott Hughes 		tty = stdin;
189*d5c9a868SElliott Hughes 	}
190*d5c9a868SElliott Hughes #ifdef USE_RAWTERM
191*d5c9a868SElliott Hughes 	if(mtools_raw_tty)
192*d5c9a868SElliott Hughes 		set_raw_tty(mode);
193*d5c9a868SElliott Hughes #endif
194*d5c9a868SElliott Hughes 	return tty;
195*d5c9a868SElliott Hughes }
196*d5c9a868SElliott Hughes 
ask_confirmation(const char * format,...)197*d5c9a868SElliott Hughes int ask_confirmation(const char *format, ...)
198*d5c9a868SElliott Hughes {
199*d5c9a868SElliott Hughes 	char ans[10];
200*d5c9a868SElliott Hughes 	va_list ap;
201*d5c9a868SElliott Hughes 
202*d5c9a868SElliott Hughes 	if(!opentty(-1))
203*d5c9a868SElliott Hughes 		return 0;
204*d5c9a868SElliott Hughes 
205*d5c9a868SElliott Hughes 	while (1) {
206*d5c9a868SElliott Hughes 		va_start(ap, format);
207*d5c9a868SElliott Hughes 		vfprintf(stderr, format, ap);
208*d5c9a868SElliott Hughes 		va_end(ap);
209*d5c9a868SElliott Hughes 		fflush(stderr);
210*d5c9a868SElliott Hughes 		fflush(opentty(-1));
211*d5c9a868SElliott Hughes 		if (mtools_raw_tty) {
212*d5c9a868SElliott Hughes 			int c = fgetc(opentty(1));
213*d5c9a868SElliott Hughes 			if(c < 0)
214*d5c9a868SElliott Hughes 				/* Treat end-of-file or error as no */
215*d5c9a868SElliott Hughes 				ans[0] = 'n';
216*d5c9a868SElliott Hughes 			else
217*d5c9a868SElliott Hughes 				ans[0] = (char) c;
218*d5c9a868SElliott Hughes 			fputs("\n", stderr);
219*d5c9a868SElliott Hughes 		} else {
220*d5c9a868SElliott Hughes 			if(fgets(ans,9, opentty(0)) == NULL)
221*d5c9a868SElliott Hughes 				/* Treat end-of-file as no */
222*d5c9a868SElliott Hughes 				ans[0] = 'n';
223*d5c9a868SElliott Hughes 		}
224*d5c9a868SElliott Hughes 		if (ans[0] == 'y' || ans[0] == 'Y')
225*d5c9a868SElliott Hughes 			return 0;
226*d5c9a868SElliott Hughes 		if (ans[0] == 'n' || ans[0] == 'N')
227*d5c9a868SElliott Hughes 			return -1;
228*d5c9a868SElliott Hughes 	}
229*d5c9a868SElliott Hughes }
230