1 /*
2   rbsb.c - terminal handling stuff for lrzsz
3   Copyright (C) until 1988 Chuck Forsberg (Omen Technology INC)
4   Copyright (C) 1994 Matt Porter, Michael D. Black
5   Copyright (C) 1996, 1997 Uwe Ohse
6 
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10   any later version.
11 
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16 
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20   02111-1307, USA.
21 
22   originally written by Chuck Forsberg
23 */
24 
25 /*
26  *  Rev 05-05-1988
27  *  ============== (not quite, but originated there :-). -- uwe
28  */
29 #include "zglobal.h"
30 
31 #include <stdio.h>
32 #include <errno.h>
33 
34 #ifndef HAVE_ERRNO_DECLARATION
35 extern int errno;
36 #endif
37 
38 #ifdef USE_SGTTY
39 #  ifdef LLITOUT
40 long Locmode;		/* Saved "local mode" for 4.x BSD "new driver" */
41 long Locbit = LLITOUT;	/* Bit SUPPOSED to disable output translations */
42 #  endif
43 #endif
44 
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
47 #endif
48 
49 #ifdef MAJOR_IN_MKDEV
50 #include <sys/mkdev.h>
51 #else
52 # ifdef MAJOR_IN_SYSMACROS
53 # include <sys/sysmacros.h>
54 # endif
55 #endif
56 
57 #if defined(HOWMANY) && HOWMANY  > 255
58 #ifndef NFGVMIN
59 Howmany must be 255 or less
60 #endif
61 #endif
62 
63 static struct {
64 	unsigned baudr;
65 	speed_t speedcode;
66 } speeds[] = {
67 	{110,	B110},
68 	{300,	B300},
69 	{600,	B600},
70 	{1200,	B1200},
71 	{2400,	B2400},
72 	{4800,	B4800},
73 	{9600,	B9600},
74 #ifdef B19200
75     {19200,  B19200},
76 #endif
77 #ifdef B38400
78     {38400,  B38400},
79 #endif
80 #ifdef B57600
81     {57600,  B57600},
82 #endif
83 #ifdef B115200
84     {115200,  B115200},
85 #endif
86 #ifdef B230400
87     {230400,  B230400},
88 #endif
89 #ifdef B460800
90     {460800,  B460800},
91 #endif
92 #ifdef EXTA
93 	{19200,	EXTA},
94 #endif
95 #ifdef EXTB
96 	{38400,	EXTB},
97 #endif
98 	{0, 0}
99 };
100 
101 static unsigned
getspeed(speed_t code)102 getspeed(speed_t code)
103 {
104 	int n;
105 
106 	for (n=0; speeds[n].baudr; ++n)
107 		if (speeds[n].speedcode == code)
108 			return speeds[n].baudr;
109 	return 38400;	/* Assume fifo if ioctl failed */
110 }
111 
112 /*
113  * return 1 if stdout and stderr are different devices
114  *  indicating this program operating with a modem on a
115  *  different line
116  */
117 int Fromcu;		/* Were called from cu or yam */
118 int
from_cu(void)119 from_cu(void)
120 {
121 #ifdef HAVE_ST_RDEV
122 	struct stat a, b;
123 #if defined(makedev)
124 	dev_t help=makedev(0,0);
125 #else
126 	int help=0;
127 #endif
128 
129 	/* in case fstat fails */
130 	a.st_rdev=b.st_rdev=a.st_dev=b.st_dev=help;
131 
132 	fstat(1, &a); fstat(2, &b);
133 
134 #if defined(major) && defined(minor)
135 	if (major(a.st_rdev) != major(b.st_rdev)
136 		|| minor(a.st_rdev) != minor(b.st_rdev))
137 		Fromcu=1;
138 	else if (major(a.st_dev) != major(b.st_dev)
139 		|| minor(a.st_dev) != minor(b.st_dev))
140 		Fromcu=1;
141 	else
142 		Fromcu=0;
143 #else
144 	Fromcu = (a.st_rdev != b.st_rdev) || (a.st_dev != b.st_dev);
145 #endif
146 #else
147 	Fromcu = 1; /* a bad guess .. */
148 #endif
149 	return Fromcu;
150 }
151 
152 
153 
154 int Twostop;		/* Use two stop bits */
155 
156 
157 #ifdef READCHECK_FIONREAD
158 /*
159  *  Return non 0 if something to read from io descriptor f
160  */
161 int
rdchk(int fd)162 rdchk(int fd)
163 {
164 	static long lf;
165 
166 	ioctl(fd, FIONREAD, &lf);
167 	return ((int) lf);
168 }
169 #endif
170 
171 #ifdef READCHECK_GETFL
172 unsigned char checked = '\0' ;
173 /*
174  * Nonblocking I/O is a bit different in System V, Release 2
175  */
176 int
rdchk(int fd)177 rdchk(int fd)
178 {
179 	int lf, savestat;
180 
181 	savestat = fcntl(fd, F_GETFL) ;
182 	if (savestat == -1)
183 		return 0;
184 #ifdef OVERLY_PARANOID
185 	if (-1==fcntl(fd, F_SETFL, savestat | O_NDELAY))
186 		return 0;
187 	lf = read(fd, &checked, 1) ;
188 	if (-1==fcntl(fd, F_SETFL, savestat)) {
189 #ifdef ENABLE_SYSLOG
190 		if (enable_syslog)
191 			lsyslog(LOG_CRIT,"F_SETFL failed in rdchk(): %s",
192 				strerror(errno));
193 #endif
194 		zpfatal("rdchk: F_SETFL failed\n"); /* lose */
195 		/* there is really no way to recover. And we can't tell
196 		 * the other side what's going on if we can't write to
197 		 * fd, but we try.
198 		 */
199 		canit(fd);
200 		exit(1);
201 	}
202 #else
203 	fcntl(fd, F_SETFL, savestat | O_NDELAY);
204 	lf = read(fd, &checked, 1) ;
205 	fcntl(fd, F_SETFL, savestat);
206 #endif
207 	return(lf == -1 && errno==EWOULDBLOCK ? 0 : lf) ;
208 }
209 #endif
210 
211 
212 
213 
214 
215 #ifdef USE_TERMIOS
216 struct termios oldtty, tty;
217 #else
218 #  if defined(USE_TERMIO)
219 struct termio oldtty, tty;
220 #  else
221 struct sgttyb oldtty, tty;
222 struct tchars oldtch, tch;
223 #  endif
224 #endif
225 
226 
227 /*
228  * mode(n)
229  *  3: save old tty stat, set raw mode with flow control
230  *  2: set XON/XOFF for sb/sz with ZMODEM or YMODEM-g
231  *  1: save old tty stat, set raw mode
232  *  0: restore original tty mode
233  */
234 int
io_mode(int fd,int n)235 io_mode(int fd, int n)
236 {
237 	static int did0 = FALSE;
238 
239 	vfile("mode:%d", n);
240 
241 	switch(n) {
242 
243 #ifdef USE_TERMIOS
244 	case 2:		/* Un-raw mode used by sz, sb when -g detected */
245 		if(!did0) {
246 			did0 = TRUE;
247 			tcgetattr(fd,&oldtty);
248 		}
249 		tty = oldtty;
250 
251 		tty.c_iflag = BRKINT|IXON;
252 
253 		tty.c_oflag = 0;	/* Transparent output */
254 
255 		tty.c_cflag &= ~PARENB;	/* Disable parity */
256 		tty.c_cflag |= CS8;	/* Set character size = 8 */
257 		if (Twostop)
258 			tty.c_cflag |= CSTOPB;	/* Set two stop bits */
259 
260 #ifdef READCHECK
261 		tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG;
262 		tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030;	/* Interrupt char */
263 #else
264 		tty.c_lflag = 0;
265 		tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? 03 : 030;	/* Interrupt char */
266 #endif
267 #ifdef _POSIX_VDISABLE
268 		if (((int) _POSIX_VDISABLE)!=(-1)) {
269 			tty.c_cc[VQUIT] = _POSIX_VDISABLE;		/* Quit char */
270 		} else {
271 			tty.c_cc[VQUIT] = -1;			/* Quit char */
272 		}
273 #else
274 		tty.c_cc[VQUIT] = -1;			/* Quit char */
275 #endif
276 #ifdef NFGVMIN
277 		tty.c_cc[VMIN] = 1;
278 #else
279 		tty.c_cc[VMIN] = 3;	 /* This many chars satisfies reads */
280 #endif
281 		tty.c_cc[VTIME] = 1;	/* or in this many tenths of seconds */
282 
283 		tcsetattr(fd,TCSADRAIN,&tty);
284 
285 		return OK;
286 	case 1:
287 	case 3:
288 		if(!did0) {
289 			did0 = TRUE;
290 			tcgetattr(fd,&oldtty);
291 		}
292 		tty = oldtty;
293 
294 		tty.c_iflag = IGNBRK;
295 		if (n==3) /* with flow control */
296 			tty.c_iflag |= IXOFF;
297 
298 		 /* No echo, crlf mapping, INTR, QUIT, delays, no erase/kill */
299 		tty.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
300 		tty.c_oflag = 0;	/* Transparent output */
301 
302 		tty.c_cflag &= ~(PARENB);	/* Same baud rate, disable parity */
303 		/* Set character size = 8 */
304 		tty.c_cflag &= ~(CSIZE);
305 		tty.c_cflag |= CS8;
306 		if (Twostop)
307 			tty.c_cflag |= CSTOPB;	/* Set two stop bits */
308 #ifdef NFGVMIN
309 		tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */
310 #else
311 		tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */
312 #endif
313 		tty.c_cc[VTIME] = 1;	/* or in this many tenths of seconds */
314 		tcsetattr(fd,TCSADRAIN,&tty);
315 		Baudrate = getspeed(cfgetospeed(&tty));
316 		return OK;
317 	case 0:
318 		if(!did0)
319 			return ERROR;
320 		tcdrain (fd); /* wait until everything is sent */
321 		tcflush (fd,TCIOFLUSH); /* flush input queue */
322 		tcsetattr (fd,TCSADRAIN,&oldtty);
323 		tcflow (fd,TCOON); /* restart output */
324 
325 		return OK;
326 #endif
327 
328 #ifdef USE_TERMIO
329 	case 2:		/* Un-raw mode used by sz, sb when -g detected */
330 		if(!did0)
331 			(void) ioctl(fd, TCGETA, &oldtty);
332 		tty = oldtty;
333 
334 		tty.c_iflag = BRKINT|IXON;
335 
336 		tty.c_oflag = 0;	/* Transparent output */
337 
338 		tty.c_cflag &= ~PARENB;	/* Disable parity */
339 		tty.c_cflag |= CS8;	/* Set character size = 8 */
340 		if (Twostop)
341 			tty.c_cflag |= CSTOPB;	/* Set two stop bits */
342 
343 
344 #ifdef READCHECK
345 		tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG;
346 		tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030;	/* Interrupt char */
347 #else
348 		tty.c_lflag = 0;
349 		tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? 03 : 030;	/* Interrupt char */
350 #endif
351 		tty.c_cc[VQUIT] = -1;			/* Quit char */
352 #ifdef NFGVMIN
353 		tty.c_cc[VMIN] = 1;
354 #else
355 		tty.c_cc[VMIN] = 3;	 /* This many chars satisfies reads */
356 #endif
357 		tty.c_cc[VTIME] = 1;	/* or in this many tenths of seconds */
358 
359 		(void) ioctl(fd, TCSETAW, &tty);
360 		did0 = TRUE;
361 		return OK;
362 	case 1:
363 	case 3:
364 		if(!did0)
365 			(void) ioctl(fd, TCGETA, &oldtty);
366 		tty = oldtty;
367 
368 		tty.c_iflag = n==3 ? (IGNBRK|IXOFF) : IGNBRK;
369 
370 		 /* No echo, crlf mapping, delays, no erase/kill */
371 		tty.c_lflag &= ~(ECHO | ICANON | ISIG);
372 
373 		tty.c_oflag = 0;	/* Transparent output */
374 
375 		tty.c_cflag &= ~PARENB;	/* Same baud rate, disable parity */
376 		tty.c_cflag |= CS8;	/* Set character size = 8 */
377 		if (Twostop)
378 			tty.c_cflag |= CSTOPB;	/* Set two stop bits */
379 #ifdef NFGVMIN
380 		tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */
381 #else
382 		tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */
383 #endif
384 		tty.c_cc[VTIME] = 1;	/* or in this many tenths of seconds */
385 		(void) ioctl(fd, TCSETAW, &tty);
386 		did0 = TRUE;
387 		Baudrate = getspeed(tty.c_cflag & CBAUD);
388 		return OK;
389 	case 0:
390 		if(!did0)
391 			return ERROR;
392 		(void) ioctl(fd, TCSBRK, 1);	/* Wait for output to drain */
393 		(void) ioctl(fd, TCFLSH, 0);	/* Flush input queue */
394 		(void) ioctl(fd, TCSETAW, &oldtty);	/* Restore modes */
395 		(void) ioctl(fd, TCXONC,1);	/* Restart output */
396 		return OK;
397 #endif
398 
399 
400 #ifdef USE_SGTTY
401 	/*
402 	 *  NOTE: this should transmit all 8 bits and at the same time
403 	 *   respond to XOFF/XON flow control.  If no FIONREAD or other
404 	 *   READCHECK alternative, also must respond to INTRRUPT char
405 	 *   This doesn't work with V7.  It should work with LLITOUT,
406 	 *   but LLITOUT was broken on the machine I tried it on.
407 	 */
408 	case 2:		/* Un-raw mode used by sz, sb when -g detected */
409 		if(!did0) {
410 			ioctl(fd, TIOCEXCL, 0);
411 			ioctl(fd, TIOCGETP, &oldtty);
412 			ioctl(fd, TIOCGETC, &oldtch);
413 #ifdef LLITOUT
414 			ioctl(fd, TIOCLGET, &Locmode);
415 #endif
416 		}
417 		tty = oldtty;
418 		tch = oldtch;
419 #ifdef READCHECK
420 		tch.t_intrc = Zmodem ? -1:030;	/* Interrupt char */
421 #else
422 		tch.t_intrc = Zmodem ? 03:030;	/* Interrupt char */
423 #endif
424 		tty.sg_flags |= (ODDP|EVENP|CBREAK);
425 		tty.sg_flags &= ~(ALLDELAY|CRMOD|ECHO|LCASE);
426 		ioctl(fd, TIOCSETP, &tty);
427 		ioctl(fd, TIOCSETC, &tch);
428 #ifdef LLITOUT
429 		ioctl(fd, TIOCLBIS, &Locbit);
430 #else
431 		bibi(99);	/* un-raw doesn't work w/o lit out */
432 #endif
433 		did0 = TRUE;
434 		return OK;
435 	case 1:
436 	case 3:
437 		if(!did0) {
438 			ioctl(fd, TIOCEXCL, 0);
439 			ioctl(fd, TIOCGETP, &oldtty);
440 			ioctl(fd, TIOCGETC, &oldtch);
441 #ifdef LLITOUT
442 			ioctl(fd, TIOCLGET, &Locmode);
443 #endif
444 		}
445 		tty = oldtty;
446 		tty.sg_flags |= RAW;
447 		tty.sg_flags &= ~ECHO;
448 		ioctl(fd, TIOCSETP, &tty);
449 		did0 = TRUE;
450 		Baudrate = getspeed(tty.sg_ospeed);
451 		return OK;
452 	case 0:
453 		if(!did0)
454 			return ERROR;
455 		ioctl(fd, TIOCSETP, &oldtty);
456 		ioctl(fd, TIOCSETC, &oldtch);
457 		ioctl(fd, TIOCNXCL, 0);
458 #ifdef LLITOUT
459 		ioctl(fd, TIOCLSET, &Locmode);
460 #endif
461 #ifdef TIOCFLUSH
462 		{ int x=1; ioctl(fd,TIOCFLUSH,&x); }
463 #endif
464 #endif
465 
466 		return OK;
467 	default:
468 		return ERROR;
469 	}
470 }
471 
472 void
sendbrk(int fd)473 sendbrk(int fd)
474 {
475 #ifdef USE_TERMIOS
476 	tcsendbreak(fd,0);
477 #endif
478 #ifdef USE_TERMIO
479 	ioctl(fd, TCSBRK, 0);
480 #endif
481 #ifdef USE_SGTTY
482 #ifdef TIOCSBRK
483 	sleep(1);
484 	ioctl(fd, TIOCSBRK, 0);
485 	sleep(1);
486 	ioctl(fd, TIOCCBRK, 0);
487 #endif
488 #endif
489 }
490 
491 void
purgeline(int fd)492 purgeline(int fd)
493 {
494 	readline_purge();
495 #ifdef TCFLSH
496 	ioctl(fd, TCFLSH, 0);
497 #else
498 	lseek(fd, 0L, 2);
499 #endif
500 }
501 
502 /* End of rbsb.c */
503