xref: /minix3/usr.bin/telnet/sys_bsd.c (revision 7348b5c52b47a1c199a1754a40bbfa360b536de2)
1  /*	$NetBSD: sys_bsd.c,v 1.33 2012/01/09 16:08:55 christos Exp $	*/
2  
3  /*
4   * Copyright (c) 1988, 1990, 1993
5   *	The Regents of the University of California.  All rights reserved.
6   *
7   * Redistribution and use in source and binary forms, with or without
8   * modification, are permitted provided that the following conditions
9   * are met:
10   * 1. Redistributions of source code must retain the above copyright
11   *    notice, this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright
13   *    notice, this list of conditions and the following disclaimer in the
14   *    documentation and/or other materials provided with the distribution.
15   * 3. Neither the name of the University nor the names of its contributors
16   *    may be used to endorse or promote products derived from this software
17   *    without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29   * SUCH DAMAGE.
30   */
31  
32  #include <sys/cdefs.h>
33  #ifndef lint
34  #if 0
35  from: static char sccsid[] = "@(#)sys_bsd.c	8.4 (Berkeley) 5/30/95";
36  #else
37  __RCSID("$NetBSD: sys_bsd.c,v 1.33 2012/01/09 16:08:55 christos Exp $");
38  #endif
39  #endif /* not lint */
40  
41  /*
42   * The following routines try to encapsulate what is system dependent
43   * (at least between 4.x and dos) which is used in telnet.c.
44   */
45  
46  
47  #include <fcntl.h>
48  #include <sys/types.h>
49  #include <sys/time.h>
50  #include <sys/socket.h>
51  #include <signal.h>
52  #include <stdlib.h>
53  #include <unistd.h>
54  #include <errno.h>
55  #include <poll.h>
56  #include <arpa/telnet.h>
57  
58  #include "ring.h"
59  #include "defines.h"
60  #include "externs.h"
61  #include "types.h"
62  
63  #define	SIG_FUNC_RET	void
64  
65  SIG_FUNC_RET susp(int);
66  SIG_FUNC_RET ayt(int);
67  
68  SIG_FUNC_RET intr(int);
69  SIG_FUNC_RET intr2(int);
70  SIG_FUNC_RET sendwin(int);
71  
72  
73  int
74  	tout,			/* Output file descriptor */
75  	tin,			/* Input file descriptor */
76  	net;
77  
78  struct	termios old_tc = { .c_iflag = 0 };
79  extern struct termios new_tc;
80  
81  # ifndef	TCSANOW
82  #  ifdef TCSETS
83  #   define	TCSANOW		TCSETS
84  #   define	TCSADRAIN	TCSETSW
85  #   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
86  #  else
87  #   ifdef TCSETA
88  #    define	TCSANOW		TCSETA
89  #    define	TCSADRAIN	TCSETAW
90  #    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
91  #   else
92  #    define	TCSANOW		TIOCSETA
93  #    define	TCSADRAIN	TIOCSETAW
94  #    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
95  #   endif
96  #  endif
97  #  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
98  #  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
99  #  ifdef CIBAUD
100  #   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
101  #  else
102  #   define	cfgetispeed(ptr)	cfgetospeed(ptr)
103  #  endif
104  # endif /* TCSANOW */
105  
106  
107  void
init_sys(void)108  init_sys(void)
109  {
110      tout = fileno(stdout);
111      tin = fileno(stdin);
112  
113      errno = 0;
114  }
115  
116  
117  int
TerminalWrite(char * buf,int n)118  TerminalWrite(char *buf, int  n)
119  {
120      return write(tout, buf, n);
121  }
122  
123  int
TerminalRead(unsigned char * buf,int n)124  TerminalRead(unsigned char *buf, int  n)
125  {
126      return read(tin, buf, n);
127  }
128  
129  /*
130   *
131   */
132  
133  int
TerminalAutoFlush(void)134  TerminalAutoFlush(void)
135  {
136      return 1;
137  }
138  
139  #ifdef	KLUDGELINEMODE
140  extern int kludgelinemode;
141  #endif
142  /*
143   * TerminalSpecialChars()
144   *
145   * Look at an input character to see if it is a special character
146   * and decide what to do.
147   *
148   * Output:
149   *
150   *	0	Don't add this character.
151   *	1	Do add this character
152   */
153  
154  int
TerminalSpecialChars(int c)155  TerminalSpecialChars(int c)
156  {
157      if (c == termIntChar) {
158  	intp();
159  	return 0;
160      } else if (c == termQuitChar) {
161  #ifdef	KLUDGELINEMODE
162  	if (kludgelinemode)
163  	    sendbrk();
164  	else
165  #endif
166  	    sendabort();
167  	return 0;
168      } else if (c == termEofChar) {
169  	if (my_want_state_is_will(TELOPT_LINEMODE)) {
170  	    sendeof();
171  	    return 0;
172  	}
173  	return 1;
174      } else if (c == termSuspChar) {
175  	sendsusp();
176  	return(0);
177      } else if (c == termFlushChar) {
178  	xmitAO();		/* Transmit Abort Output */
179  	return 0;
180      } else if (!MODE_LOCAL_CHARS(globalmode)) {
181  	if (c == termKillChar) {
182  	    xmitEL();
183  	    return 0;
184  	} else if (c == termEraseChar) {
185  	    xmitEC();		/* Transmit Erase Character */
186  	    return 0;
187  	}
188      }
189      return 1;
190  }
191  
192  
193  /*
194   * Flush output to the terminal
195   */
196  
197  void
TerminalFlushOutput(void)198  TerminalFlushOutput(void)
199  {
200      int com = 0;
201      (void) ioctl(fileno(stdout), TIOCFLUSH, &com);
202  }
203  
204  void
TerminalSaveState(void)205  TerminalSaveState(void)
206  {
207      tcgetattr(0, &old_tc);
208  
209      new_tc = old_tc;
210  }
211  
212  cc_t *
tcval(int func)213  tcval(int func)
214  {
215      switch(func) {
216      case SLC_IP:	return(&termIntChar);
217      case SLC_ABORT:	return(&termQuitChar);
218      case SLC_EOF:	return(&termEofChar);
219      case SLC_EC:	return(&termEraseChar);
220      case SLC_EL:	return(&termKillChar);
221      case SLC_XON:	return(&termStartChar);
222      case SLC_XOFF:	return(&termStopChar);
223      case SLC_FORW1:	return(&termForw1Char);
224      case SLC_FORW2:	return(&termForw2Char);
225      case SLC_AO:	return(&termFlushChar);
226      case SLC_SUSP:	return(&termSuspChar);
227      case SLC_EW:	return(&termWerasChar);
228      case SLC_RP:	return(&termRprntChar);
229      case SLC_LNEXT:	return(&termLiteralNextChar);
230      case SLC_AYT:	return(&termAytChar);
231  
232      case SLC_SYNCH:
233      case SLC_BRK:
234      case SLC_EOR:
235      default:
236  	return((cc_t *)0);
237      }
238  }
239  
240  void
TerminalDefaultChars(void)241  TerminalDefaultChars(void)
242  {
243      memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
244  }
245  
246  #ifdef notdef
247  void
TerminalRestoreState(void)248  TerminalRestoreState(void)
249  {
250  }
251  #endif
252  
253  /*
254   * TerminalNewMode - set up terminal to a specific mode.
255   *	MODE_ECHO: do local terminal echo
256   *	MODE_FLOW: do local flow control
257   *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
258   *	MODE_EDIT: do local line editing
259   *
260   *	Command mode:
261   *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
262   *		local echo
263   *		local editing
264   *		local xon/xoff
265   *		local signal mapping
266   *
267   *	Linemode:
268   *		local/no editing
269   *	Both Linemode and Single Character mode:
270   *		local/remote echo
271   *		local/no xon/xoff
272   *		local/no signal mapping
273   */
274  
275  
276  void
TerminalNewMode(int f)277  TerminalNewMode(int f)
278  {
279      static int prevmode = 0;
280      struct termios tmp_tc;
281      int onoff;
282      int old;
283      cc_t esc;
284  
285      globalmode = f&~MODE_FORCE;
286      if (prevmode == f)
287  	return;
288  
289      /*
290       * Write any outstanding data before switching modes
291       * ttyflush() returns 0 only when there is no more data
292       * left to write out, it returns -1 if it couldn't do
293       * anything at all, otherwise it returns 1 + the number
294       * of characters left to write.
295  #ifndef	USE_TERMIO
296       * We would really like to ask the kernel to wait for the output
297       * to drain, like we can do with the TCSADRAIN, but we don't have
298       * that option.  The only ioctl that waits for the output to
299       * drain, TIOCSETP, also flushes the input queue, which is NOT
300       * what we want (TIOCSETP is like TCSADFLUSH).
301  #endif
302       */
303      old = ttyflush(SYNCHing|flushout);
304      if (old < 0 || old > 1) {
305  	tcgetattr(tin, &tmp_tc);
306  	do {
307  	    /*
308  	     * Wait for data to drain, then flush again.
309  	     */
310  	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
311  	    old = ttyflush(SYNCHing|flushout);
312  	} while (old < 0 || old > 1);
313      }
314  
315      old = prevmode;
316      prevmode = f&~MODE_FORCE;
317      tmp_tc = new_tc;
318  
319      if (f&MODE_ECHO) {
320  	tmp_tc.c_lflag |= ECHO;
321  	tmp_tc.c_oflag |= ONLCR;
322  	if (crlf)
323  		tmp_tc.c_iflag |= ICRNL;
324      } else {
325  	tmp_tc.c_lflag &= ~ECHO;
326  	tmp_tc.c_oflag &= ~ONLCR;
327  # ifdef notdef
328  	if (crlf)
329  		tmp_tc.c_iflag &= ~ICRNL;
330  # endif
331      }
332  
333      if ((f&MODE_FLOW) == 0) {
334  	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
335      } else {
336  	if (restartany < 0) {
337  		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
338  	} else if (restartany > 0) {
339  		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
340  	} else {
341  		tmp_tc.c_iflag |= IXOFF|IXON;
342  		tmp_tc.c_iflag &= ~IXANY;
343  	}
344      }
345  
346      if ((f&MODE_TRAPSIG) == 0) {
347  	tmp_tc.c_lflag &= ~ISIG;
348  	localchars = 0;
349      } else {
350  	tmp_tc.c_lflag |= ISIG;
351  	localchars = 1;
352      }
353  
354      if (f&MODE_EDIT) {
355  	tmp_tc.c_lflag |= ICANON;
356      } else {
357  	tmp_tc.c_lflag &= ~ICANON;
358  	tmp_tc.c_iflag &= ~ICRNL;
359  	tmp_tc.c_cc[VMIN] = 1;
360  	tmp_tc.c_cc[VTIME] = 0;
361      }
362  
363      if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
364  	tmp_tc.c_lflag &= ~IEXTEN;
365      }
366  
367      if (f&MODE_SOFT_TAB) {
368  # ifdef	OXTABS
369  	tmp_tc.c_oflag |= OXTABS;
370  # endif
371  # ifdef	TABDLY
372  	tmp_tc.c_oflag &= ~TABDLY;
373  	tmp_tc.c_oflag |= TAB3;
374  # endif
375      } else {
376  # ifdef	OXTABS
377  	tmp_tc.c_oflag &= ~OXTABS;
378  # endif
379  # ifdef	TABDLY
380  	tmp_tc.c_oflag &= ~TABDLY;
381  # endif
382      }
383  
384      if (f&MODE_LIT_ECHO) {
385  # ifdef	ECHOCTL
386  	tmp_tc.c_lflag &= ~ECHOCTL;
387  # endif
388      } else {
389  # ifdef	ECHOCTL
390  	tmp_tc.c_lflag |= ECHOCTL;
391  # endif
392      }
393  
394      if (f == -1) {
395  	onoff = 0;
396      } else {
397  	if (f & MODE_INBIN)
398  		tmp_tc.c_iflag &= ~ISTRIP;
399  	else
400  		tmp_tc.c_iflag |= ISTRIP;
401  	if (f & MODE_OUTBIN) {
402  		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
403  		tmp_tc.c_cflag |= CS8;
404  		tmp_tc.c_oflag &= ~OPOST;
405  	} else {
406  		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
407  		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
408  		tmp_tc.c_oflag |= OPOST;
409  	}
410  	onoff = 1;
411      }
412  
413      if (f != -1) {
414  	(void) signal(SIGTSTP, susp);
415  	(void) signal(SIGINFO, ayt);
416  #if	defined(USE_TERMIO) && defined(NOKERNINFO)
417  	tmp_tc.c_lflag |= NOKERNINFO;
418  #endif
419  	/*
420  	 * We don't want to process ^Y here.  It's just another
421  	 * character that we'll pass on to the back end.  It has
422  	 * to process it because it will be processed when the
423  	 * user attempts to read it, not when we send it.
424  	 */
425  # ifdef	VDSUSP
426  	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
427  # endif
428  	/*
429  	 * If the VEOL character is already set, then use VEOL2,
430  	 * otherwise use VEOL.
431  	 */
432  	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
433  	if ((tmp_tc.c_cc[VEOL] != esc)
434  # ifdef	VEOL2
435  	    && (tmp_tc.c_cc[VEOL2] != esc)
436  # endif
437  	    ) {
438  		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
439  		    tmp_tc.c_cc[VEOL] = esc;
440  # ifdef	VEOL2
441  		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
442  		    tmp_tc.c_cc[VEOL2] = esc;
443  # endif
444  	}
445      } else {
446  	(void) signal(SIGINFO, (void (*)(int)) ayt_status);
447  	(void) signal(SIGTSTP, SIG_DFL);
448  	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
449  	tmp_tc = old_tc;
450      }
451      if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
452  	tcsetattr(tin, TCSANOW, &tmp_tc);
453  
454      ioctl(tin, FIONBIO, (char *)&onoff);
455      ioctl(tout, FIONBIO, (char *)&onoff);
456  #if	defined(TN3270)
457      if (noasynchtty == 0) {
458  	ioctl(tin, FIOASYNC, (char *)&onoff);
459      }
460  #endif	/* defined(TN3270) */
461  
462  }
463  
464  void
TerminalSpeeds(long * ispeed,long * ospeed)465  TerminalSpeeds(long *ispeed, long *ospeed)
466  {
467      long in, out;
468  
469      out = cfgetospeed(&old_tc);
470      in = cfgetispeed(&old_tc);
471      if (in == 0)
472  	in = out;
473  
474  	*ispeed = in;
475  	*ospeed = out;
476  }
477  
478  int
TerminalWindowSize(long * rows,long * cols)479  TerminalWindowSize(long *rows, long *cols)
480  {
481      struct winsize ws;
482  
483      if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
484  	*rows = ws.ws_row;
485  	*cols = ws.ws_col;
486  	return 1;
487      }
488      return 0;
489  }
490  
491  int
NetClose(int fd)492  NetClose(int fd)
493  {
494      return close(fd);
495  }
496  
497  
498  void
NetNonblockingIO(int fd,int onoff)499  NetNonblockingIO(int fd, int onoff)
500  {
501      ioctl(fd, FIONBIO, (char *)&onoff);
502  }
503  
504  #ifdef TN3270
505  void
NetSigIO(int fd,int onoff)506  NetSigIO(int fd, int onoff)
507  {
508      ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
509  }
510  
511  void
NetSetPgrp(int fd)512  NetSetPgrp(int fd)
513  {
514      int myPid;
515  
516      myPid = getpid();
517      fcntl(fd, F_SETOWN, myPid);
518  }
519  #endif	/*defined(TN3270)*/
520  
521  /*
522   * Various signal handling routines.
523   */
524  
525  /* ARGSUSED */
526  SIG_FUNC_RET
intr(int sig)527  intr(int sig)
528  {
529      if (localchars) {
530  	intp();
531  	return;
532      }
533      setcommandmode();
534      longjmp(toplevel, -1);
535  }
536  
537  /* ARGSUSED */
538  SIG_FUNC_RET
intr2(int sig)539  intr2(int sig)
540  {
541      if (localchars) {
542  #ifdef	KLUDGELINEMODE
543  	if (kludgelinemode)
544  	    sendbrk();
545  	else
546  #endif
547  	    sendabort();
548  	return;
549      }
550  }
551  
552  /* ARGSUSED */
553  SIG_FUNC_RET
susp(int sig)554  susp(int sig)
555  {
556      if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
557  	return;
558      if (localchars)
559  	sendsusp();
560  }
561  
562  /* ARGSUSED */
563  SIG_FUNC_RET
sendwin(int sig)564  sendwin(int sig)
565  {
566      if (connected) {
567  	sendnaws();
568      }
569  }
570  
571  /* ARGSUSED */
572  SIG_FUNC_RET
ayt(int sig)573  ayt(int sig)
574  {
575      if (connected)
576  	sendayt();
577      else
578  	ayt_status();
579  }
580  
581  
582  void
sys_telnet_init(void)583  sys_telnet_init(void)
584  {
585      (void) signal(SIGINT, intr);
586      (void) signal(SIGQUIT, intr2);
587      (void) signal(SIGPIPE, SIG_IGN);
588      (void) signal(SIGWINCH, sendwin);
589      (void) signal(SIGTSTP, susp);
590      (void) signal(SIGINFO, ayt);
591  
592      setconnmode(0);
593  
594      NetNonblockingIO(net, 1);
595  
596  #ifdef TN3270
597      if (noasynchnet == 0) {			/* DBX can't handle! */
598  	NetSigIO(net, 1);
599  	NetSetPgrp(net);
600      }
601  #endif	/* defined(TN3270) */
602  
603      if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
604  	perror("SetSockOpt");
605      }
606  }
607  
608  /*
609   * Process rings -
610   *
611   *	This routine tries to fill up/empty our various rings.
612   *
613   *	The parameter specifies whether this is a poll operation,
614   *	or a block-until-something-happens operation.
615   *
616   *	The return value is 1 if something happened, 0 if not, < 0 if an
617   *	error occurred.
618   */
619  
620  int
process_rings(int netin,int netout,int netex,int ttyin,int ttyout,int dopoll)621  process_rings(int netin, int netout, int netex, int ttyin, int ttyout,
622      int dopoll)		/* If 0, then block until something to do */
623  {
624      struct pollfd set[3];
625      int c;
626  		/* One wants to be a bit careful about setting returnValue
627  		 * to one, since a one implies we did some useful work,
628  		 * and therefore probably won't be called to block next
629  		 * time (TN3270 mode only).
630  		 */
631      int returnValue = 0;
632  
633      set[0].fd = net;
634      set[0].events = (netout ? POLLOUT : 0) | (netin ? POLLIN : 0) |
635  	(netex ? POLLPRI : 0);
636      set[1].fd = tout;
637      set[1].events = ttyout ? POLLOUT : 0;
638      set[2].fd = tin;
639      set[2].events = ttyin ? POLLIN : 0;
640  
641      if ((c = poll(set, 3, dopoll ? 0 : INFTIM)) < 0) {
642  	if (c == -1) {
643  		    /*
644  		     * we can get EINTR if we are in line mode,
645  		     * and the user does an escape (TSTP), or
646  		     * some other signal generator.
647  		     */
648  	    if (errno == EINTR) {
649  		return 0;
650  	    }
651  #ifdef TN3270
652  		    /*
653  		     * we can get EBADF if we were in transparent
654  		     * mode, and the transcom process died.
655  		    */
656  	    if (errno == EBADF)
657  		return 0;
658  #endif /* defined(TN3270) */
659  		    /* I don't like this, does it ever happen? */
660  	    printf("sleep(5) from telnet, after poll\r\n");
661  	    sleep(5);
662  	}
663  	return 0;
664      }
665  
666      /*
667       * Any urgent data?
668       */
669      if (set[0].revents & POLLPRI) {
670  	SYNCHing = 1;
671  	(void) ttyflush(1);	/* flush already enqueued data */
672      }
673  
674      /*
675       * Something to read from the network...
676       */
677      if (set[0].revents & POLLIN) {
678  	int canread;
679  
680  	canread = ring_empty_consecutive(&netiring);
681  	c = recv(net, (char *)netiring.supply, canread, 0);
682  	if (c < 0 && errno == EWOULDBLOCK) {
683  	    c = 0;
684  	} else if (c <= 0) {
685  	    return -1;
686  	}
687  	if (netdata) {
688  	    Dump('<', netiring.supply, c);
689  	}
690  	if (c)
691  	    ring_supplied(&netiring, c);
692  	returnValue = 1;
693      }
694  
695      /*
696       * Something to read from the tty...
697       */
698      if (set[2].revents & POLLIN) {
699  	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
700  	if (c < 0 && errno == EIO)
701  	    c = 0;
702  	if (c < 0 && errno == EWOULDBLOCK) {
703  	    c = 0;
704  	} else {
705  	    if (c < 0) {
706  		return -1;
707  	    }
708  	    if (c == 0) {
709  		/* must be an EOF... */
710  		if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
711  		    *ttyiring.supply = termEofChar;
712  		    c = 1;
713  		} else {
714  		    clienteof = 1;
715  		    shutdown(net, 1);
716  		    return 0;
717  		}
718  	    }
719  	    if (termdata) {
720  		Dump('<', ttyiring.supply, c);
721  	    }
722  	    ring_supplied(&ttyiring, c);
723  	}
724  	returnValue = 1;		/* did something useful */
725      }
726  
727      if (set[0].revents & POLLOUT) {
728  	returnValue |= netflush();
729      }
730  
731      if (set[1].revents & (POLLHUP|POLLNVAL))
732  	return(-1);
733  
734      if (set[1].revents & POLLOUT) {
735  	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
736      }
737  
738      return returnValue;
739  }
740