1 /* @(#)ttymodes.c	1.35 16/08/14 Copyright 1986,1995-2016 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)ttymodes.c	1.35 16/08/14 Copyright 1986,1995-2016 J. Schilling";
6 #endif
7 /*
8  *	ttymodes.c
9  *
10  *	Terminal handling for bsh
11  *
12  *	Copyright (c) 1986,1995-2016 J. Schilling
13  */
14 /*
15  * The contents of this file are subject to the terms of the
16  * Common Development and Distribution License, Version 1.0 only
17  * (the "License").  You may not use this file except in compliance
18  * with the License.
19  *
20  * See the file CDDL.Schily.txt in this distribution for details.
21  * A copy of the CDDL is also available via the Internet at
22  * http://www.opensource.org/licenses/cddl1.txt
23  *
24  * When distributing Covered Code, include this CDDL HEADER in each
25  * file and include the License file CDDL.Schily.txt from this distribution.
26  */
27 
28 #include <schily/stdio.h>
29 #include <schily/unistd.h>
30 #define	putch	dos_putch	/* Avoid DOS/curses putch() type clash */
31 #define	ungetch	dos_ungetch	/* Avoid DOS/curses ungetch() type clash */
32 #include <schily/termios.h>
33 #undef	putch			/* Restore our old value */
34 #undef	ungetch			/* Restore our old value */
35 
36 #include "bsh.h"
37 
38 #ifdef INTERACTIVE
39 
40 #define	OLD_MODE	1
41 #define	INS_MODE	2
42 #define	APP_MODE	3
43 
44 extern	pid_t	mypgrp;
45 
46 	BOOL	ins_mode	= FALSE;
47 	BOOL	i_should_echo	= FALSE;
48 
49 LOCAL	BOOL	cmdmodes	= FALSE;
50 
51 
52 LOCAL	BOOL	tty_init	= FALSE;
53 
54 #ifdef	USE_V7_TTY
55 
56 LOCAL	struct sgttyb	ins	= {0};
57 LOCAL	struct sgttyb	app	= {0};
58 LOCAL	struct sgttyb	old	= {0};
59 LOCAL	struct tchars	oldt	= {0};
60 LOCAL	struct tchars	inst	= {0};
61 LOCAL	struct tchars	appt	= {0};
62 #ifdef	TIOCSLTC
63 LOCAL	struct ltchars	oldl	= {0};
64 LOCAL	struct ltchars	insl	= {0};
65 LOCAL	struct ltchars	appl	= {0};
66 #endif
67 
68 #ifdef	NTTYDISC
69 LOCAL	int	olddisc	= -1;
70 LOCAL	int	disc	= NTTYDISC;
71 #endif	/* NTTYDISC */
72 
73 #else	/* !USE_V7_TTY */
74 
75 #ifdef	USE_TERMIOS
76 LOCAL	struct termios	ins	= {0};
77 LOCAL	struct termios	app	= {0};
78 LOCAL	struct termios	old	= {0};
79 #endif
80 
81 #endif	/* !USE_V7_TTY */
82 
83 #ifdef	JOBCONTROL
84 LOCAL	pid_t	oldpgrp	= 0;
85 #endif	/* JOBCONTROL */
86 
87 EXPORT	void	reset_line_disc		__PR((void));
88 EXPORT	void	reset_tty_pgrp		__PR((void));
89 EXPORT	void	reset_tty_modes		__PR((void));
90 EXPORT	void	set_append_modes	__PR((FILE *f));
91 EXPORT	void	set_insert_modes	__PR((FILE *f));
92 #ifdef	JOBCONTROL
93 LOCAL	void	init_tty_pgrp		__PR((void));
94 #endif
95 EXPORT	void	get_tty_modes		__PR((FILE *f));
96 LOCAL	void	init_tty_modes		__PR((void));
97 LOCAL	void	set_tty_modes		__PR((FILE *f, int mode));
98 EXPORT	pid_t	tty_getpgrp		__PR((int f));
99 EXPORT	int	tty_setpgrp		__PR((int f, pid_t pgrp));
100 
101 EXPORT void
reset_line_disc()102 reset_line_disc()
103 {
104 #if	defined(USE_V7_TTY) && defined(NTTYDISC)
105 	FILE	*f;
106 
107 	if ((f = getinfile()) && olddisc != NTTYDISC)
108 		ioctl(fdown(f), TIOCSETD, (char *)&olddisc);
109 
110 #endif	/* defined(USE_V7_TTY) && defined(NTTYDISC) */
111 }
112 
113 EXPORT void
reset_tty_pgrp()114 reset_tty_pgrp()
115 {
116 #ifdef	JOBCONTROL
117 	FILE	*f;
118 
119 	if ((f = getinfile()) != 0 && oldpgrp != 0)
120 		tty_setpgrp(fdown(f), oldpgrp);
121 #endif	/* JOBCONTROL */
122 }
123 
124 EXPORT void
reset_tty_modes()125 reset_tty_modes()
126 {
127 #if	defined(USE_V7_TTY) && defined(NTTYDISC)
128 
129 	if (olddisc < 0)
130 		init_line_disc();
131 
132 #endif	/* defined(USE_V7_TTY) && defined(NTTYDISC) */
133 
134 	set_tty_modes(getinfile(), OLD_MODE);
135 	cmdmodes = FALSE;
136 }
137 
138 EXPORT void
set_append_modes(f)139 set_append_modes(f)
140 	FILE	*f;
141 {
142 	if (ins_mode) {
143 		set_tty_modes(f, APP_MODE);
144 		i_should_echo	= TRUE;
145 		ins_mode	= FALSE;
146 		cmdmodes	= TRUE;
147 	}
148 }
149 
150 EXPORT void
set_insert_modes(f)151 set_insert_modes(f)
152 	FILE	*f;
153 {
154 	if (!ins_mode) {
155 		set_tty_modes(f, INS_MODE);
156 		ins_mode = TRUE;
157 		cmdmodes = TRUE;
158 	}
159 }
160 
161 /*
162  *	Beim Umschalten der Linedisziplin geht der Input verloren.
163  *	Um nach dem Starten des 'bsh' jederzeit Kommandos eingeben zu
164  *	koennen wird nur einmal vor dem Starten des ersten
165  *	interaktven Kommandos auf die neue Linedisziplin umgeschaltet.
166  *	Dies geschieht in 'reset_tty_modes()'.
167  *	Die erste Zeile wird mit der davor aktiven Disziplin editiert.
168  *	Da die neue Linedisziplin nur fuer die Prozesskontrolle von
169  *	laufenden Kommandos benoetigt wird, ist das kein Fehler.
170  */
171 #if	defined(USE_V7_TTY) && defined(NTTYDISC)
172 EXPORT void
init_line_disc()173 init_line_disc()
174 {
175 	int	fno;
176 	FILE	*f;
177 
178 	if (f = getinfile()) {
179 		fno = fdown(f);
180 		ioctl(fno, TIOCGETD, (char *)&olddisc);
181 		if (olddisc != NTTYDISC)
182 			ioctl(fno, TIOCSETD, (char *)&disc);
183 	}
184 }
185 #endif	/* defined(USE_V7_TTY) && defined(NTTYDISC) */
186 
187 #ifdef	JOBCONTROL
188 LOCAL void
init_tty_pgrp()189 init_tty_pgrp()
190 {
191 	int	fno;
192 	FILE	*f;
193 
194 	if ((f = getinfile()) != NULL) {
195 		fno = fdown(f);
196 		oldpgrp = tty_getpgrp(fno);
197 		tty_setpgrp(fno, mypgrp);
198 	}
199 }
200 #endif	/* JOBCONTROL */
201 
202 EXPORT void
get_tty_modes(f)203 get_tty_modes(f)
204 	FILE	*f;
205 {
206 	if (!cmdmodes) {
207 #ifdef	USE_V7_TTY
208 		ioctl(fdown(f), TIOCGETP, (char *)&old);
209 		ins.sg_ispeed = old.sg_ispeed;
210 		ins.sg_ospeed = old.sg_ospeed;
211 		app.sg_ispeed = old.sg_ispeed;
212 		app.sg_ospeed = old.sg_ospeed;
213 		ins.sg_flags = old.sg_flags;
214 		app.sg_flags = old.sg_flags;
215 		ins.sg_flags |= (CBREAK|CRMOD);
216 		ins.sg_flags &= ~(ECHO|RAW);
217 		app.sg_flags |= (CBREAK|CRMOD);
218 		app.sg_flags &= ~(ECHO|RAW);
219 		ioctl(fdown(f), TIOCGETC, (char *)&oldt);
220 		inst.t_startc	= oldt.t_startc;
221 		inst.t_stopc	= oldt.t_stopc;
222 		appt.t_startc	= oldt.t_startc;
223 		appt.t_stopc	= oldt.t_stopc;
224 #ifdef	TIOCSLTC
225 		ioctl(fdown(f), TIOCGLTC, (char *)&oldl);
226 #endif
227 #else	/* !USE_V7_TTY */
228 #ifdef	USE_TERMIOS
229 #ifdef	TCSANOW
230 		tcgetattr(fdown(f), &old);
231 #else
232 		ioctl(fdown(f), TCGETS, (char *)&old);
233 #endif
234 
235 		app.c_iflag = ins.c_iflag = old.c_iflag;
236 		app.c_oflag = ins.c_oflag = old.c_oflag;
237 		app.c_cflag = ins.c_cflag = old.c_cflag;
238 		app.c_lflag = ins.c_lflag = old.c_lflag;
239 
240 		ins.c_iflag |= (IGNBRK);
241 		ins.c_iflag &= ~(BRKINT|INLCR|ICRNL);
242 		ins.c_oflag |= (OPOST);
243 		ins.c_lflag &= ~(ISIG|ICANON|ECHO);
244 
245 		app.c_iflag |= (IGNBRK);
246 		app.c_iflag &= ~(BRKINT|INLCR|ICRNL);
247 		app.c_oflag |= (OPOST);
248 		app.c_lflag &= ~(ISIG|ICANON|ECHO);
249 #endif	/* USE_TERMIOS */
250 #endif	/* !USE_V7_TTY */
251 		if (!tty_init) {
252 			init_tty_modes();
253 #ifdef	JOBCONTROL
254 			init_tty_pgrp();
255 #endif	/* JOBCONTROL */
256 			tty_init = TRUE;
257 		}
258 	}
259 }
260 
261 
262 LOCAL void
init_tty_modes()263 init_tty_modes()
264 {
265 #ifdef	USE_V7_TTY
266 	movebytes((char *)&old, (char *)&app, sizeof (old));
267 	movebytes((char *)&old, (char *)&ins, sizeof (old));
268 	ins.sg_erase	= -1;
269 	ins.sg_kill	= -1;
270 	app.sg_erase	= -1;
271 	app.sg_kill	= -1;
272 	ins.sg_flags |= (CBREAK|CRMOD);
273 	ins.sg_flags &= ~(ECHO|RAW);
274 	app.sg_flags |= (CBREAK|CRMOD);
275 	app.sg_flags &= ~(ECHO|RAW);
276 	movebytes((char *)&oldt, (char *)&inst, sizeof (inst));
277 	inst.t_intrc	= -1;
278 	inst.t_quitc	= -1;
279 #ifdef	__never__
280 	/* Auf keinen Fall !!! */
281 	inst.t_startc	= -1;
282 	inst.t_stopc	= -1;
283 #endif
284 	inst.t_eofc	= -1;
285 	inst.t_brkc	= -1;
286 #ifdef	TIOCSLTC
287 	insl.t_suspc	= -1;
288 	insl.t_dsuspc	= -1;
289 	insl.t_rprntc	= -1;
290 	insl.t_flushc	= -1;
291 	insl.t_werasc	= -1;
292 	insl.t_lnextc	= -1;
293 	movebytes((char *)&insl, (char *)&appl, sizeof (insl));
294 #endif
295 	movebytes((char *)&inst, (char *)&appt, sizeof (inst));
296 #else
297 #ifdef	USE_TERMIOS
298 	movebytes((char *)&old, (char *)&app, sizeof (old));
299 	movebytes((char *)&old, (char *)&ins, sizeof (old));
300 
301 	ins.c_iflag |= (IGNBRK);
302 	ins.c_iflag &= ~(BRKINT|INLCR|ICRNL);
303 	ins.c_oflag |= (OPOST);
304 	ins.c_lflag &= ~(ISIG|ICANON|ECHO);
305 	ins.c_cc[VMIN] = 1;
306 	ins.c_cc[VTIME] = 0;
307 #ifdef	VREPRINT
308 	ins.c_cc[VREPRINT] = _POSIX_VDISABLE;
309 #endif
310 #ifdef	VDISCARD
311 	ins.c_cc[VDISCARD] = _POSIX_VDISABLE;
312 #endif
313 #ifdef	VWERASE
314 	ins.c_cc[VWERASE] = _POSIX_VDISABLE;
315 #endif
316 #ifdef	VLNEXT
317 	ins.c_cc[VLNEXT] = _POSIX_VDISABLE;
318 #endif
319 	app.c_iflag |= (IGNBRK);
320 	app.c_iflag &= ~(BRKINT|INLCR|ICRNL);
321 	app.c_oflag |= (OPOST);
322 	app.c_lflag &= ~(ISIG|ICANON|ECHO);
323 	app.c_cc[VMIN] = 1;
324 	app.c_cc[VTIME] = 0;
325 #ifdef	VREPRINT
326 	app.c_cc[VREPRINT] = _POSIX_VDISABLE;
327 #endif
328 #ifdef	VDISCARD
329 	app.c_cc[VDISCARD] = _POSIX_VDISABLE;
330 #endif
331 #ifdef	VWERASE
332 	app.c_cc[VWERASE] = _POSIX_VDISABLE;
333 #endif
334 #ifdef	VLNEXT
335 	app.c_cc[VLNEXT] = _POSIX_VDISABLE;
336 #endif
337 #endif	/* USE_TERMIOS */
338 #endif	/* USE_V7_TTY */
339 }
340 
341 
342 LOCAL void
set_tty_modes(f,mode)343 set_tty_modes(f, mode)
344 	FILE	*f;
345 	int	mode;
346 {
347 	int	fno;
348 
349 	if (f == NULL)
350 		return;
351 
352 	fno = fdown(f);
353 
354 	switch (mode) {
355 
356 #ifdef	USE_V7_TTY
357 	case	OLD_MODE:
358 			ioctl(fno, TIOCSETN, (char *)&old);
359 			ioctl(fno, TIOCSETC, (char *)&oldt);
360 #ifdef	TIOCSLTC
361 				ioctl(fno, TIOCSLTC, (char *)&oldl);
362 #endif
363 			break;
364 	case	APP_MODE:
365 			ioctl(fno, TIOCSETN, (char *)&app);
366 			ioctl(fno, TIOCSETC, (char *)&appt);
367 #ifdef	TIOCSLTC
368 				ioctl(fno, TIOCSLTC, (char *)&appl);
369 #endif
370 			break;
371 	case	INS_MODE:
372 			ioctl(fno, TIOCSETN, (char *)&ins);
373 			ioctl(fno, TIOCSETC, (char *)&inst);
374 #ifdef	TIOCSLTC
375 				ioctl(fno, TIOCSLTC, (char *)&insl);
376 #endif
377 			break;
378 #else
379 #ifdef	USE_TERMIOS
380 #ifdef	TCSANOW
381 
382 	case	OLD_MODE:
383 			tcsetattr(fno, TCSADRAIN, &old);
384 			break;
385 	case	APP_MODE:
386 			tcsetattr(fno, TCSADRAIN, &app);
387 			break;
388 	case	INS_MODE:
389 			tcsetattr(fno, TCSADRAIN, &ins);
390 			break;
391 #else	/* !TCSANOW */
392 
393 	case	OLD_MODE:
394 			ioctl(fno, TCSETSW, (char *)&old);
395 			break;
396 	case	APP_MODE:
397 			ioctl(fno, TCSETSW, (char *)&app);
398 			break;
399 	case	INS_MODE:
400 			ioctl(fno, TCSETSW, (char *)&ins);
401 			break;
402 #endif	/* !TCSANOW */
403 #endif	/* USE_TERMIOS */
404 #endif	/* USE_V7_TTY */
405 	}
406 }
407 
408 #endif /* INTERACTIVE */
409 
410 #ifdef	JOBCONTROL
411 EXPORT pid_t
tty_getpgrp(f)412 tty_getpgrp(f)
413 	int	f;
414 {
415 #ifdef	HAVE_TCGETPGRP
416 	return (tcgetpgrp(f));
417 #else
418 #ifdef	TIOCGPGRP
419 	pid_t	pgrp;
420 
421 	if (ioctl(f, TIOCGPGRP, (char *)&pgrp) < 0)
422 		return ((pid_t)-1);
423 	return (pgrp);
424 #else
425 #ifdef	ENOSYS
426 	seterrno(ENOSYS);
427 #else
428 	seterrno(EINVAL);
429 #endif
430 	return ((pid_t)-1);
431 #endif
432 #endif	/* HAVE_TCGETPGRP */
433 }
434 
435 #ifdef	PROTOTYPES
436 EXPORT int
tty_setpgrp(int f,pid_t pgrp)437 tty_setpgrp(int f, pid_t pgrp)
438 #else
439 EXPORT int
440 tty_setpgrp(f, pgrp)
441 	int	f;
442 	pid_t	pgrp;
443 #endif
444 {
445 #ifdef	HAVE_TCGETPGRP
446 	return (tcsetpgrp(f, pgrp));
447 #else
448 #ifdef	TIOCSPGRP
449 	return (ioctl(f, TIOCSPGRP, (char *)&pgrp));
450 #else
451 	return (0);
452 #endif
453 #endif	/* HAVE_TCSETPGRP */
454 }
455 #else
456 EXPORT pid_t
tty_getpgrp(f)457 tty_getpgrp(f)
458 	int	f;
459 {
460 #ifdef	ENOSYS
461 	seterrno(ENOSYS);
462 #else
463 	seterrno(EINVAL);
464 #endif
465 	return ((pid_t)-1);
466 }
467 
468 EXPORT int
tty_setpgrp(f,pgrp)469 tty_setpgrp(f, pgrp)
470 	int	f;
471 	pid_t	pgrp;
472 {
473 	return (0);
474 }
475 #endif
476