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