1/* serial.c
2   The serial port communication routines for Unix.
3
4   Copyright (C) 1991, 1992, 1993, 1994, 1995, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#if USE_RCS_ID
28const char serial_rcsid[] = "$Id: serial.c,v 1.78 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31#include "uudefs.h"
32#include "uuconf.h"
33#include "system.h"
34#include "conn.h"
35#include "sysdep.h"
36
37#include <errno.h>
38#include <ctype.h>
39
40#if HAVE_SYS_PARAM_H
41#include <sys/param.h>
42#endif
43
44#if HAVE_LIMITS_H
45#include <limits.h>
46#endif
47
48#if HAVE_TLI
49#if HAVE_TIUSER_H
50#include <tiuser.h>
51#else /* ! HAVE_TIUSER_H */
52#if HAVE_XTI_H
53#include <xti.h>
54#endif /* HAVE_XTI_H */
55#endif /* ! HAVE_TIUSER_H */
56#endif /* HAVE_TLI */
57
58#if HAVE_FCNTL_H
59#include <fcntl.h>
60#else
61#if HAVE_SYS_FILE_H
62#include <sys/file.h>
63#endif
64#endif
65
66#ifndef O_RDONLY
67#define O_RDONLY 0
68#define O_WRONLY 1
69#define O_RDWR 2
70#endif
71
72#ifndef O_NOCTTY
73#define O_NOCTTY 0
74#endif
75
76#ifndef FD_CLOEXEC
77#define FD_CLOEXEC 1
78#endif
79
80#if HAVE_SYS_IOCTL_H || HAVE_TXADDCD
81#include <sys/ioctl.h>
82#endif
83
84#if HAVE_SELECT
85#if HAVE_SYS_TIME_H
86#include <sys/time.h>
87#endif
88#if HAVE_SYS_SELECT_H
89#include <sys/select.h>
90#endif
91#endif
92
93#if HAVE_TIME_H
94#if ! HAVE_SYS_TIME_H || ! HAVE_SELECT || TIME_WITH_SYS_TIME
95#include <time.h>
96#endif
97#endif
98
99#if HAVE_STRIP_BUG && HAVE_BSD_TTY
100#include <termio.h>
101#endif
102
103#if HAVE_SVR4_LOCKFILES
104/* Get the right definitions for major and minor.  */
105#if MAJOR_IN_MKDEV
106#include <sys/mkdev.h>
107#endif /* MAJOR_IN_MKDEV */
108#if MAJOR_IN_SYSMACROS
109#include <sys/sysmacros.h>
110#endif /* MAJOR_IN_SYSMACROS */
111#if ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS
112#ifndef major
113#define major(i) (((i) >> 8) & 0xff)
114#endif
115#ifndef minor
116#define minor(i) ((i) & 0xff)
117#endif
118#endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */
119#endif /* HAVE_SVR4_LOCKFILES */
120
121#if HAVE_DEV_INFO
122#include <sys/dev.h>
123#endif
124
125#if HAVE_SYS_TERMIOX_H
126#include <sys/termiox.h>
127#endif
128
129/* Get definitions for both O_NONBLOCK and O_NDELAY.  */
130#ifndef O_NDELAY
131#ifdef FNDELAY
132#define O_NDELAY FNDELAY
133#else /* ! defined (FNDELAY) */
134#define O_NDELAY 0
135#endif /* ! defined (FNDELAY) */
136#endif /* ! defined (O_NDELAY) */
137
138#ifndef O_NONBLOCK
139#ifdef FNBLOCK
140#define O_NONBLOCK FNBLOCK
141#else /* ! defined (FNBLOCK) */
142#define O_NONBLOCK 0
143#endif /* ! defined (FNBLOCK) */
144#endif /* ! defined (O_NONBLOCK) */
145
146#if O_NDELAY == 0 && O_NONBLOCK == 0
147 #error No way to do nonblocking I/O
148#endif
149
150/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA.  */
151#ifndef EAGAIN
152#ifndef EWOULDBLOCK
153#define EAGAIN (-1)
154#define EWOULDBLOCK (-1)
155#else /* defined (EWOULDBLOCK) */
156#define EAGAIN EWOULDBLOCK
157#endif /* defined (EWOULDBLOCK) */
158#else /* defined (EAGAIN) */
159#ifndef EWOULDBLOCK
160#define EWOULDBLOCK EAGAIN
161#endif /* ! defined (EWOULDBLOCK) */
162#endif /* defined (EAGAIN) */
163
164#ifndef ENODATA
165#define ENODATA EAGAIN
166#endif
167
168/* Make sure we have a definition for MAX_INPUT.  */
169#ifndef MAX_INPUT
170#define MAX_INPUT (256)
171#endif
172
173/* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal.
174   Otherwise, if we have the TIOCEXCL ioctl call, we have to open the
175   terminal before we know that it is unlocked.  */
176#ifdef TIOCSINUSE
177#define HAVE_TIOCSINUSE 1
178#else
179#ifdef TIOCEXCL
180#define HAVE_TIOCEXCL 1
181#endif
182#endif
183
184#if HAVE_TLI
185extern int t_errno;
186extern char *t_errlist[];
187extern int t_nerr;
188#endif
189
190/* Determine bits to clear for the various terminal control fields for
191   HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS.  */
192
193/* These fields are defined on some systems, and I am told that it
194   does not hurt to clear them, and it sometimes helps.  */
195#ifndef IMAXBEL
196#define IMAXBEL 0
197#endif
198
199#ifndef PENDIN
200#define PENDIN 0
201#endif
202
203#if HAVE_SYSV_TERMIO
204#define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
205		      | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
206		      | IXON | IXANY | IXOFF | IMAXBEL)
207#define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
208		      | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
209		      | VTDLY | FFDLY)
210#define ICLEAR_CFLAG (CBAUD | CSIZE | PARENB | PARODD)
211#define ISET_CFLAG (CS8 | CREAD | HUPCL)
212#define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
213		      | ECHONL | NOFLSH | PENDIN)
214#endif
215#if HAVE_POSIX_TERMIOS
216#define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
217		      | INLCR | INPCK | ISTRIP | IXOFF | IXON \
218		      | PARMRK | IMAXBEL)
219#define ICLEAR_OFLAG (OPOST)
220#define ICLEAR_CFLAG (CSIZE | PARENB | PARODD)
221#define ISET_CFLAG (CS8 | CREAD | HUPCL)
222#define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
223		      | ISIG | NOFLSH | TOSTOP | PENDIN)
224#endif
225
226enum tclocal_setting
227{
228  SET_CLOCAL,
229  CLEAR_CLOCAL,
230  IGNORE_CLOCAL
231};
232
233/* Local functions.  */
234
235static RETSIGTYPE usalarm P((int isig));
236static boolean fsserial_init P((struct sconnection *qconn,
237				const struct sconncmds *qcmds,
238				const char *zdevice));
239static void usserial_free P((struct sconnection *qconn));
240static boolean fsserial_lockfile P((boolean flok,
241				    const struct sconnection *));
242static boolean fsserial_lock P((struct sconnection *qconn,
243				boolean fin, boolean fuser));
244static boolean fsserial_unlock P((struct sconnection *qconn));
245static boolean fsserial_open P((struct sconnection *qconn, long ibaud,
246				boolean fwait, boolean fuser,
247				enum tclocal_setting tlocal));
248static boolean fsstdin_open P((struct sconnection *qconn, long ibaud,
249			       boolean fwait, boolean fuser));
250static boolean fsmodem_open P((struct sconnection *qconn, long ibaud,
251			       boolean fwait, boolean fuser));
252static boolean fsdirect_open P((struct sconnection *qconn, long ibaud,
253				boolean fwait, boolean fuser));
254static boolean fsblock P((struct ssysdep_conn *q, boolean fblock));
255static boolean fsserial_close P((struct ssysdep_conn *q));
256static boolean fsstdin_close P((struct sconnection *qconn,
257				pointer puuconf,
258				struct uuconf_dialer *qdialer,
259				boolean fsuccess));
260static boolean fsmodem_close P((struct sconnection *qconn,
261				pointer puuconf,
262				struct uuconf_dialer *qdialer,
263				boolean fsuccess));
264static boolean fsdirect_close P((struct sconnection *qconn,
265				 pointer puuconf,
266				 struct uuconf_dialer *qdialer,
267				 boolean fsuccess));
268static boolean fsserial_break P((struct sconnection *qconn));
269static boolean fsstdin_break P((struct sconnection *qconn));
270static boolean fsserial_set P((struct sconnection *qconn,
271			       enum tparitysetting tparity,
272			       enum tstripsetting tstrip,
273			       enum txonxoffsetting txonxoff));
274static boolean fsstdin_set P((struct sconnection *qconn,
275			       enum tparitysetting tparity,
276			       enum tstripsetting tstrip,
277			       enum txonxoffsetting txonxoff));
278static boolean fsmodem_carrier P((struct sconnection *qconn,
279				  boolean fcarrier));
280static boolean fsserial_hardflow P((struct sconnection *qconn,
281				    boolean fhardflow));
282static boolean fsrun_chat P((int oread, int owrite, char **pzprog));
283static long isserial_baud P((struct sconnection *qconn));
284
285/* The command table for standard input ports.  */
286
287static const struct sconncmds sstdincmds =
288{
289  usserial_free,
290  NULL, /* pflock */
291  NULL, /* pfunlock */
292  fsstdin_open,
293  fsstdin_close,
294  NULL, /* pfdial */
295  fsdouble_read,
296  fsdouble_write,
297  fsysdep_conn_io,
298  fsstdin_break,
299  fsstdin_set,
300  NULL, /* pfcarrier */
301  fsdouble_chat,
302  isserial_baud
303};
304
305/* The command table for modem ports.  */
306
307static const struct sconncmds smodemcmds =
308{
309  usserial_free,
310  fsserial_lock,
311  fsserial_unlock,
312  fsmodem_open,
313  fsmodem_close,
314  fmodem_dial,
315  fsysdep_conn_read,
316  fsysdep_conn_write,
317  fsysdep_conn_io,
318  fsserial_break,
319  fsserial_set,
320  fsmodem_carrier,
321  fsysdep_conn_chat,
322  isserial_baud
323};
324
325/* The command table for direct ports.  */
326
327static const struct sconncmds sdirectcmds =
328{
329  usserial_free,
330  fsserial_lock,
331  fsserial_unlock,
332  fsdirect_open,
333  fsdirect_close,
334  NULL, /* pfdial */
335  fsysdep_conn_read,
336  fsysdep_conn_write,
337  fsysdep_conn_io,
338  fsserial_break,
339  fsserial_set,
340  NULL, /* pfcarrier */
341  fsysdep_conn_chat,
342  isserial_baud
343};
344
345/* If the system will let us set both O_NDELAY and O_NONBLOCK, we do
346   so.  This is because some ancient drivers on some systems appear to
347   look for one but not the other.  Some other systems will give an
348   EINVAL error if we attempt to set both, so we use a static global
349   to hold the value we want to set.  If we get EINVAL, we change the
350   global and try again (if some system gives an error other than
351   EINVAL, the code will have to be modified).  */
352static int iSunblock = O_NDELAY | O_NONBLOCK;
353
354/* This code handles SIGALRM.  See the discussion above
355   fsysdep_conn_read.  Normally we ignore SIGALRM, but the handler
356   will temporarily be set to this function, which should set fSalarm
357   and then either longjmp or schedule another SIGALRM.  fSalarm is
358   never referred to outside of this file, but we don't make it static
359   to try to fool compilers which don't understand volatile.  */
360
361volatile sig_atomic_t fSalarm;
362
363static RETSIGTYPE
364usalarm (isig)
365     int isig ATTRIBUTE_UNUSED;
366{
367#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
368  (void) signal (isig, usalarm);
369#endif
370
371  fSalarm = TRUE;
372
373#if HAVE_RESTARTABLE_SYSCALLS
374  longjmp (sSjmp_buf, 1);
375#else
376  alarm (1);
377#endif
378}
379
380/* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and
381   SIGPIPE and another to restore the original state.  When these
382   functions are called (in fsysdep_modem_close) SIGHUP is being
383   ignored.  The routines are isblocksigs, which returns a value of
384   type HELD_SIG_MASK and usunblocksigs which takes a single argument
385   of type HELD_SIG_MASK.  */
386
387#if HAVE_SIGPROCMASK
388
389/* Use the POSIX sigprocmask call.  */
390
391#define HELD_SIG_MASK sigset_t
392
393static sigset_t isblocksigs P((void));
394
395static sigset_t
396isblocksigs ()
397{
398  sigset_t sblock, sold;
399
400  /* These expressions need an extra set of parentheses to avoid a bug
401     in SCO 3.2.2.  */
402  (void) (sigemptyset (&sblock));
403  (void) (sigaddset (&sblock, SIGINT));
404  (void) (sigaddset (&sblock, SIGQUIT));
405  (void) (sigaddset (&sblock, SIGTERM));
406  (void) (sigaddset (&sblock, SIGPIPE));
407
408  (void) sigprocmask (SIG_BLOCK, &sblock, &sold);
409  return sold;
410}
411
412#define usunblocksigs(s) \
413  ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL))
414
415#else /* ! HAVE_SIGPROCMASK */
416#if HAVE_SIGBLOCK
417
418/* Use the BSD sigblock and sigsetmask calls.  */
419
420#define HELD_SIG_MASK int
421
422#ifndef sigmask
423#define sigmask(i) (1 << ((i) - 1))
424#endif
425
426#define isblocksigs() \
427  sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \
428	    | sigmask (SIGTERM) | sigmask (SIGPIPE))
429
430#define usunblocksigs(i) ((void) sigsetmask (i))
431
432#else /* ! HAVE_SIGBLOCK */
433
434#if HAVE_SIGHOLD
435
436/* Use the SVR3 sighold and sigrelse calls.  */
437
438#define HELD_SIG_MASK int
439
440static int isblocksigs P((void));
441
442static int
443isblocksigs ()
444{
445  sighold (SIGINT);
446  sighold (SIGQUIT);
447  sighold (SIGTERM);
448  sighold (SIGPIPE);
449  return 0;
450}
451
452static void usunblocksigs P((int));
453
454/*ARGSUSED*/
455static void
456usunblocksigs (i)
457     int i;
458{
459  sigrelse (SIGINT);
460  sigrelse (SIGQUIT);
461  sigrelse (SIGTERM);
462  sigrelse (SIGPIPE);
463}
464
465#else /* ! HAVE_SIGHOLD */
466
467/* We have no way to block signals.  This system will suffer from a
468   race condition in fsysdep_modem_close.  */
469
470#define HELD_SIG_MASK int
471
472#define isblocksigs() 0
473
474#define usunblocksigs(i)
475
476#endif /* ! HAVE_SIGHOLD */
477#endif /* ! HAVE_SIGBLOCK */
478#endif /* ! HAVE_SIGPROCMASK */
479
480/* Initialize a connection for use on a serial port.  */
481
482static boolean
483fsserial_init (qconn, qcmds, zdevice)
484     struct sconnection *qconn;
485     const struct sconncmds *qcmds;
486     const char *zdevice;
487{
488  struct ssysdep_conn *q;
489
490  q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
491  if (zdevice == NULL
492      && qconn->qport != NULL
493      && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
494    zdevice = qconn->qport->uuconf_zname;
495  if (zdevice == NULL)
496    q->zdevice = NULL;
497  else if (*zdevice == '/')
498    q->zdevice = zbufcpy (zdevice);
499  else
500    {
501      size_t clen;
502
503      clen = strlen (zdevice);
504      q->zdevice = zbufalc (sizeof "/dev/" + clen);
505      memcpy (q->zdevice, "/dev/", sizeof "/dev/" - 1);
506      memcpy (q->zdevice + sizeof "/dev/" - 1, zdevice, clen);
507      q->zdevice[sizeof "/dev/" + clen - 1] = '\0';
508    }
509  q->o = -1;
510  q->ord = -1;
511  q->owr = -1;
512  q->ftli = FALSE;
513  qconn->psysdep = (pointer) q;
514  qconn->qcmds = qcmds;
515  return TRUE;
516}
517
518/* Initialize a connection for use on standard input.  */
519
520boolean
521fsysdep_stdin_init (qconn)
522     struct sconnection *qconn;
523{
524  /* chmod /dev/tty to prevent other users from writing messages to
525     it.  This is essentially `mesg n'.  */
526  (void) chmod ("/dev/tty", S_IRUSR | S_IWUSR);
527  return fsserial_init (qconn, &sstdincmds, (const char *) NULL);
528}
529
530/* Initialize a connection for use on a modem port.  */
531
532boolean
533fsysdep_modem_init (qconn)
534     struct sconnection *qconn;
535{
536  return fsserial_init (qconn, &smodemcmds,
537			qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
538}
539
540/* Initialize a connection for use on a direct port.  */
541
542boolean
543fsysdep_direct_init (qconn)
544     struct sconnection *qconn;
545{
546  return fsserial_init (qconn, &sdirectcmds,
547			qconn->qport->uuconf_u.uuconf_sdirect.uuconf_zdevice);
548}
549
550/* Free up a serial port.  */
551
552static void
553usserial_free (qconn)
554     struct sconnection *qconn;
555{
556  struct ssysdep_conn *qsysdep;
557
558  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
559  ubuffree (qsysdep->zdevice);
560  xfree ((pointer) qsysdep);
561  qconn->psysdep = NULL;
562}
563
564#if HAVE_SEQUENT_LOCKFILES
565#define LCK_TEMPLATE "LCK..tty"
566#else
567#define LCK_TEMPLATE "LCK.."
568#endif
569
570/* This routine is used for both locking and unlocking.  It is the
571   only routine which knows how to translate a device name into the
572   name of a lock file.  If it can't figure out a name, it does
573   nothing and returns TRUE.  */
574
575static boolean
576fsserial_lockfile (flok, qconn)
577     boolean flok;
578     const struct sconnection *qconn;
579{
580  struct ssysdep_conn *qsysdep;
581  const char *z;
582  char *zalc;
583  boolean fret;
584
585  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
586  if (qconn->qport == NULL)
587    z = NULL;
588  else
589    z = qconn->qport->uuconf_zlockname;
590  zalc = NULL;
591  if (z == NULL)
592    {
593#if HAVE_QNX_LOCKFILES
594      {
595	nid_t idevice_nid;
596	char abdevice_nid[13]; /* length of long, a period, and a NUL */
597	size_t cdevice_nid;
598	const char *zbase;
599	size_t clen;
600
601        /* If the node ID is explicitly specified as part of the
602           pathname to the device, use that.  Otherwise, presume the
603           device is local to the current node. */
604        if (qsysdep->zdevice[0] == '/' && qsysdep->zdevice[1] == '/')
605          idevice_nid = (nid_t) strtol (qsysdep->zdevice + 2,
606					(char **) NULL, 10);
607        else
608          idevice_nid = getnid ();
609
610        sprintf (abdevice_nid, "%ld.", (long) idevice_nid);
611        cdevice_nid = strlen (abdevice_nid);
612
613 	zbase = strrchr (qsysdep->zdevice, '/') + 1;
614 	clen = strlen (zbase);
615
616        zalc = zbufalc (sizeof LCK_TEMPLATE + cdevice_nid + clen);
617
618	memcpy (zalc, LCK_TEMPLATE, sizeof LCK_TEMPLATE - 1);
619	memcpy (zalc + sizeof LCK_TEMPLATE - 1, abdevice_nid, cdevice_nid);
620	memcpy (zalc + sizeof LCK_TEMPLATE - 1 + cdevice_nid,
621		zbase, clen + 1);
622
623	z = zalc;
624      }
625#else /* ! HAVE_QNX_LOCKFILES */
626#if ! HAVE_SVR4_LOCKFILES
627      {
628	const char *zbase;
629	size_t clen;
630
631	zbase = strrchr (qsysdep->zdevice, '/') + 1;
632	clen = strlen (zbase);
633	zalc = zbufalc (sizeof LCK_TEMPLATE + clen);
634	memcpy (zalc, LCK_TEMPLATE, sizeof LCK_TEMPLATE - 1);
635	memcpy (zalc + sizeof LCK_TEMPLATE - 1, zbase, clen + 1);
636#if HAVE_SCO_LOCKFILES
637	{
638	  char *zl;
639
640	  zl = zalc + sizeof LCK_TEMPLATE + clen - 2;
641	  if (isupper (*zl))
642	    *zl = tolower (*zl);
643	}
644#endif
645	z = zalc;
646      }
647#else /* HAVE_SVR4_LOCKFILES */
648      {
649	struct stat s;
650
651	if (stat (qsysdep->zdevice, &s) != 0)
652	  {
653	    ulog (LOG_ERROR, "stat (%s): %s", qsysdep->zdevice,
654		  strerror (errno));
655	    return FALSE;
656	  }
657	zalc = zbufalc (sizeof "LK.1234567890.1234567890.1234567890");
658	sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev),
659		 major (s.st_rdev), minor (s.st_rdev));
660	z = zalc;
661      }
662#endif /* HAVE_SVR4_LOCKFILES */
663#endif /* ! HAVE_QNX_LOCKFILES */
664    }
665
666  if (flok)
667    fret = fsdo_lock (z, FALSE, (boolean *) NULL);
668  else
669    fret = fsdo_unlock (z, FALSE);
670
671#if HAVE_COHERENT_LOCKFILES
672  if (fret)
673    {
674      if (flok)
675	{
676	  if (lockttyexist (z + sizeof LCK_TEMPLATE - 1))
677	    {
678	      ulog (LOG_NORMAL, "%s: port already locked",
679		    z + sizeof LCK_TEMPLATE - 1);
680	      fret = FALSE;
681	    }
682	  else
683	    fret = fscoherent_disable_tty (z + sizeof LCK_TEMPLATE - 1,
684					   &qsysdep->zenable);
685	}
686      else
687	{
688	  fret = TRUE;
689	  if (qsysdep->zenable != NULL)
690	    {
691	      const char *azargs[3];
692	      int aidescs[3];
693	      pid_t ipid;
694
695	      azargs[0] = "/etc/enable";
696	      azargs[1] = qsysdep->zenable;
697	      azargs[2] = NULL;
698	      aidescs[0] = SPAWN_NULL;
699	      aidescs[1] = SPAWN_NULL;
700	      aidescs[2] = SPAWN_NULL;
701
702	      ipid = ixsspawn (azargs, aidescs, TRUE, FALSE,
703			       (const char *) NULL, TRUE, TRUE,
704			       (const char *) NULL, (const char *) NULL,
705			       (const char *) NULL);
706	      if (ipid < 0)
707		{
708		  ulog (LOG_ERROR, "ixsspawn (/etc/enable %s): %s",
709			qsysdep->zenable, strerror (errno));
710		  fret = FALSE;
711		}
712	      else
713		{
714		  if (ixswait ((unsigned long) ipid, (const char *) NULL)
715		      == 0)
716		    fret = TRUE;
717		  else
718		    fret = FALSE;
719		}
720	      ubuffree (qsysdep->zenable);
721	      qsysdep->zenable = NULL;
722	    }
723	}
724    }
725#endif /* HAVE_COHERENT_LOCKFILES */
726
727  ubuffree (zalc);
728  return fret;
729}
730
731/* If we can mark a modem line in use, then when we lock a port we
732   must open it and mark it in use.  We can't wait until the actual
733   open because we can't fail out if it is locked then.  */
734
735static boolean
736fsserial_lock (qconn, fin, fuser)
737     struct sconnection *qconn;
738     boolean fin;
739     boolean fuser;
740{
741  if (! fsserial_lockfile (TRUE, qconn))
742    return FALSE;
743
744#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL || HAVE_DEV_INFO
745  /* Open the line and try to mark it in use.  */
746  {
747    struct ssysdep_conn *qsysdep;
748    int iflag;
749    uid_t ieuid;
750    gid_t iegid;
751
752    qsysdep = (struct ssysdep_conn *) qconn->psysdep;
753
754    if (fin)
755      iflag = 0;
756    else
757      iflag = iSunblock;
758
759    if (fuser)
760      {
761	if (! fsuser_perms (&ieuid, &iegid))
762	  {
763	    (void) fsserial_lockfile (FALSE, qconn);
764	    return FALSE;
765	  }
766      }
767
768    qsysdep->o = open (qsysdep->zdevice, O_RDWR | iflag);
769    if (qsysdep->o < 0)
770      {
771#if O_NONBLOCK != 0
772	if (! fin && iSunblock != O_NONBLOCK && errno == EINVAL)
773	  {
774	    iSunblock = O_NONBLOCK;
775	    qsysdep->o = open (qsysdep->zdevice,
776			       O_RDWR | O_NONBLOCK);
777	  }
778#endif
779	if (qsysdep->o < 0)
780	  {
781	    int ierr;
782
783	    ierr = errno;
784	    if (fuser)
785	      (void) fsuucp_perms ((long) ieuid, (long) iegid);
786	    if (ierr != EBUSY)
787	      ulog (LOG_ERROR, "open (%s): %s", qsysdep->zdevice,
788		    strerror (ierr));
789	    (void) fsserial_lockfile (FALSE, qconn);
790	    return FALSE;
791	  }
792      }
793
794    if (fuser)
795      {
796	if (! fsuucp_perms ((long) ieuid, (long) iegid))
797	  {
798	    (void) close (qsysdep->o);
799	    qsysdep->o = -1;
800	    (void) fsserial_lockfile (FALSE, qconn);
801	    return FALSE;
802	  }
803      }
804
805#if HAVE_TIOCSINUSE
806    /* If we can't mark it in use, return FALSE to indicate that the
807       lock failed.  */
808    if (ioctl (qsysdep->o, TIOCSINUSE, 0) < 0)
809      {
810	if (errno != EALREADY)
811	  ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno));
812#ifdef TIOCNOTTY
813	(void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
814#endif
815	(void) close (qsysdep->o);
816	qsysdep->o = -1;
817	(void) fsserial_lockfile (FALSE, qconn);
818	return FALSE;
819      }
820#endif
821
822#if HAVE_DEV_INFO
823    /* QNX programs "lock" a serial port by simply opening it and
824       checking if some other program also has the port open.  If the
825       count of openers is greater than one, the program presumes the
826       port is "locked" and backs off.  This isn't really "locking" of
827       course, but it pretty much seems to work.  This can result in
828       dropping incoming connections if an outgoing connection is
829       started at exactly the same time.  It would probably be better
830       to stop using the lock files at all for this case, but that
831       would involve more complex changes to the code, and I'm afraid
832       I would break something.  -- Joe Wells <jbw@cs.bu.edu>  */
833    {
834      struct _dev_info_entry sdevinfo;
835
836      if (dev_info (qsysdep->o, &sdevinfo) == -1)
837        {
838          ulog (LOG_ERROR, "dev_info: %s", strerror (errno));
839          sdevinfo.open_count = 2; /* force presumption of "locked" */
840        }
841      if (sdevinfo.open_count != 1)
842        {
843#ifdef TIOCNOTTY
844          (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
845#endif /* TIOCNOTTY */
846          (void) close (qsysdep->o);
847          qsysdep->o = -1;
848          (void) fsserial_lockfile (FALSE, qconn);
849          return FALSE;
850        }
851    }
852#endif /* HAVE_DEV_INFO */
853
854    if (fcntl (qsysdep->o, F_SETFD,
855	       fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
856      {
857	ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
858#ifdef TIOCNOTTY
859	(void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
860#endif
861	(void) close (qsysdep->o);
862	qsysdep->o = -1;
863	(void) fsserial_lockfile (FALSE, qconn);
864	return FALSE;
865      }
866  }
867#endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
868
869  return TRUE;
870}
871
872/* Unlock a modem or direct port.  */
873
874static boolean
875fsserial_unlock (qconn)
876     struct sconnection *qconn;
877{
878  boolean fret;
879  struct ssysdep_conn *qsysdep;
880
881  fret = TRUE;
882
883  /* The file may have been opened by fsserial_lock, so close it here
884     if necessary.  */
885  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
886  if (qsysdep->o >= 0)
887    {
888#ifdef TIOCNOTTY
889      (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
890#endif
891      if (close (qsysdep->o) < 0)
892	{
893	  ulog (LOG_ERROR, "close: %s", strerror (errno));
894	  fret = FALSE;
895	}
896      qsysdep->o = -1;
897    }
898
899  if (! fsserial_lockfile (FALSE, qconn))
900    fret = FALSE;
901
902  return fret;
903}
904
905/* A table to map baud rates into index numbers.  */
906
907#if HAVE_POSIX_TERMIOS
908typedef speed_t baud_code;
909#else
910typedef int baud_code;
911#endif
912
913static struct sbaud_table
914{
915  baud_code icode;
916  long ibaud;
917} asSbaud_table[] =
918{
919  { B50, 50 },
920  { B75, 75 },
921  { B110, 110 },
922  { B134, 134 },
923  { B150, 150 },
924  { B200, 200 },
925  { B300, 300 },
926  { B600, 600 },
927  { B1200, 1200 },
928  { B1800, 1800 },
929  { B2400, 2400 },
930  { B4800, 4800 },
931  { B9600, 9600 },
932#ifdef B19200
933  { B19200, 19200 },
934#else /* ! defined (B19200) */
935#ifdef EXTA
936  { EXTA, 19200 },
937#endif /* EXTA */
938#endif /* ! defined (B19200) */
939#ifdef B38400
940  { B38400, 38400 },
941#else /* ! defined (B38400) */
942#ifdef EXTB
943  { EXTB, 38400 },
944#endif /* EXTB */
945#endif /* ! defined (B38400) */
946#ifdef B57600
947  { B57600, 57600 },
948#endif
949#ifdef B76800
950  { B76800, 76800 },
951#endif
952#ifdef B115200
953  { B115200, 115200 },
954#endif
955#ifdef B230400
956  { B230400, 230400 },
957#else
958#ifdef _B230400
959  { _B230400, 230400 },
960#endif /* _B230400 */
961#endif /* ! defined (B230400) */
962#ifdef B460800
963  { B460800, 460800 },
964#else
965#ifdef _B460800
966  { _B460800, 460800 },
967#endif /* _B460800 */
968#endif /* ! defined (B460800) */
969#ifdef B500000
970  { B500000, 500000 },
971#endif
972#ifdef B576000
973  { B576000, 576000 },
974#endif
975#ifdef B921600
976  { B921600, 921600 },
977#endif
978#ifdef B1000000
979  { B1000000, 1000000 },
980#endif
981#ifdef B1152000
982  { B1152000, 1152000 },
983#endif
984#ifdef B1500000
985  { B1500000, 1500000 },
986#endif
987#ifdef B2000000
988  { B2000000, 2000000 },
989#endif
990#ifdef B2500000
991  { B2500000, 2500000 },
992#endif
993#ifdef B3000000
994  { B3000000, 3000000 },
995#endif
996#ifdef B3500000
997  { B3500000, 3500000 },
998#endif
999#ifdef B4000000
1000  { B4000000, 4000000 },
1001#endif
1002  { B0, 0 }
1003};
1004
1005#define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0])
1006
1007#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1008/* Hold the MIN value for the terminal to avoid setting it
1009   unnecessarily.  */
1010static int cSmin;
1011#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
1012
1013/* Open a serial line.  This sets the terminal settings.  We begin in
1014   seven bit mode and let the protocol change if necessary.  If fwait
1015   is FALSE we open the terminal in non-blocking mode.  If fuser is
1016   true we open the port using the user's permissions.  The tlocal
1017   parameter indicates whether to set, clear, or ignore CLOCAL.  */
1018
1019static boolean
1020fsserial_open (qconn, ibaud, fwait, fuser, tlocal)
1021     struct sconnection *qconn;
1022     long ibaud;
1023     boolean fwait;
1024     boolean fuser;
1025     enum tclocal_setting tlocal;
1026{
1027  struct ssysdep_conn *q;
1028  baud_code ib;
1029
1030  q = (struct ssysdep_conn *) qconn->psysdep;
1031
1032  if (q->zdevice != NULL)
1033    {
1034#if LOG_DEVICE_PREFIX
1035      ulog_device (q->zdevice);
1036#else
1037      const char *z;
1038
1039      if (strncmp (q->zdevice, "/dev/", sizeof "/dev/" - 1) == 0)
1040	z = q->zdevice + sizeof "/dev/" - 1;
1041      else
1042	z = q->zdevice;
1043      ulog_device (z);
1044#endif
1045    }
1046  else
1047    {
1048      const char *zport;
1049      boolean fdummy;
1050
1051#if DEBUG > 0
1052      if (qconn->qport != NULL &&
1053	  qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
1054	ulog (LOG_FATAL, "fsserial_open: Can't happen");
1055#endif
1056      zport = zsysdep_port_name (&fdummy);
1057      if (zport != NULL)
1058	ulog_device (zport);
1059    }
1060
1061  ib = B0;
1062  if (ibaud != 0)
1063    {
1064      size_t i;
1065
1066      for (i = 0; i < CBAUD_TABLE; i++)
1067	if (asSbaud_table[i].ibaud == ibaud)
1068	  break;
1069      if (i >= CBAUD_TABLE)
1070	{
1071	  ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud);
1072	  return FALSE;
1073	}
1074      ib = asSbaud_table[i].icode;
1075    }
1076
1077  /* The port may have already been opened by the locking routine.  */
1078  if (q->o < 0)
1079    {
1080      int iflag;
1081      uid_t ieuid;
1082      gid_t iegid;
1083
1084      if (fwait)
1085	iflag = 0;
1086      else
1087	iflag = iSunblock;
1088
1089      if (fuser)
1090	{
1091	  if (! fsuser_perms (&ieuid, &iegid))
1092	    return FALSE;
1093	}
1094
1095      q->o = open (q->zdevice, O_RDWR | iflag);
1096      if (q->o < 0)
1097	{
1098#if O_NONBLOCK != 0
1099	  if (! fwait && iSunblock != O_NONBLOCK && errno == EINVAL)
1100	    {
1101	      iSunblock = O_NONBLOCK;
1102	      q->o = open (q->zdevice, O_RDWR | O_NONBLOCK);
1103	    }
1104#endif
1105	  if (q->o < 0)
1106	    {
1107	      int ierr;
1108
1109	      ierr = errno;
1110	      if (fuser)
1111		(void) fsuucp_perms ((long) ieuid, (long) iegid);
1112	      ulog (LOG_ERROR, "open (%s): %s", q->zdevice,
1113		    strerror (ierr));
1114	      return FALSE;
1115	    }
1116	}
1117
1118      if (fuser)
1119	{
1120	  if (! fsuucp_perms ((long) ieuid, (long) iegid))
1121	    return FALSE;
1122	}
1123
1124      if (fcntl (q->o, F_SETFD, fcntl (q->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
1125	{
1126	  ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
1127	  return FALSE;
1128	}
1129    }
1130
1131  /* Get the port flags, and make sure the ports are blocking.  */
1132
1133  q->iflags = fcntl (q->o, F_GETFL, 0);
1134  if (q->iflags < 0)
1135    {
1136      ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
1137      return FALSE;
1138    }
1139  q->iwr_flags = -1;
1140
1141  if (! fsblock (q, TRUE))
1142    return FALSE;
1143
1144  if (! fgetterminfo (q->o, &q->sorig))
1145    {
1146      q->fterminal = FALSE;
1147      return TRUE;
1148    }
1149
1150  q->fterminal = TRUE;
1151
1152  q->snew = q->sorig;
1153
1154#if HAVE_BSD_TTY
1155
1156  q->snew.stty.sg_flags = RAW | ANYP;
1157  if (ibaud == 0)
1158    ib = q->snew.stty.sg_ospeed;
1159  else
1160    {
1161      q->snew.stty.sg_ispeed = ib;
1162      q->snew.stty.sg_ospeed = ib;
1163    }
1164
1165  /* We don't want to receive any interrupt characters.  */
1166  q->snew.stchars.t_intrc = -1;
1167  q->snew.stchars.t_quitc = -1;
1168  q->snew.stchars.t_eofc = -1;
1169  q->snew.stchars.t_brkc = -1;
1170  q->snew.sltchars.t_suspc = -1;
1171  q->snew.sltchars.t_rprntc = -1;
1172  q->snew.sltchars.t_dsuspc = -1;
1173  q->snew.sltchars.t_flushc = -1;
1174  q->snew.sltchars.t_werasc = -1;
1175  q->snew.sltchars.t_lnextc = -1;
1176
1177#ifdef NTTYDISC
1178  /* We want to use the ``new'' terminal driver so that we can use the
1179     local mode bits to control XON/XOFF.  */
1180  {
1181    int iparam;
1182
1183    if (ioctl (q->o, TIOCGETD, &iparam) >= 0
1184	&& iparam != NTTYDISC)
1185      {
1186	iparam = NTTYDISC;
1187	(void) ioctl (q->o, TIOCSETD, &iparam);
1188      }
1189  }
1190#endif
1191
1192#ifdef TIOCHPCL
1193  /* When the file is closed, hang up the line.  This is a safety
1194     measure in case the program crashes.  */
1195  (void) ioctl (q->o, TIOCHPCL, 0);
1196#endif
1197
1198#ifdef TIOCFLUSH
1199  {
1200    int iparam;
1201
1202    /* Flush pending input.  */
1203#ifdef FREAD
1204    iparam = FREAD;
1205#else
1206    iparam = 0;
1207#endif
1208    (void) ioctl (q->o, TIOCFLUSH, &iparam);
1209  }
1210#endif /* TIOCFLUSH */
1211
1212#endif /* HAVE_BSD_TTY */
1213
1214#if HAVE_SYSV_TERMIO
1215
1216  if (ibaud == 0)
1217    ib = q->snew.c_cflag & CBAUD;
1218
1219  q->snew.c_iflag &=~ ICLEAR_IFLAG;
1220  q->snew.c_oflag &=~ ICLEAR_OFLAG;
1221  q->snew.c_cflag &=~ ICLEAR_CFLAG;
1222  q->snew.c_cflag |= ib | ISET_CFLAG;
1223  q->snew.c_lflag &=~ ICLEAR_LFLAG;
1224  cSmin = 1;
1225  q->snew.c_cc[VMIN] = cSmin;
1226  q->snew.c_cc[VTIME] = 1;
1227
1228#ifdef TCFLSH
1229  /* Flush pending input.  */
1230  (void) ioctl (q->o, TCFLSH, 0);
1231#endif
1232
1233#endif /* HAVE_SYSV_TERMIO */
1234
1235#if HAVE_POSIX_TERMIOS
1236
1237  if (ibaud == 0)
1238    ib = cfgetospeed (&q->snew);
1239
1240  q->snew.c_iflag &=~ ICLEAR_IFLAG;
1241  q->snew.c_oflag &=~ ICLEAR_OFLAG;
1242  q->snew.c_cflag &=~ ICLEAR_CFLAG;
1243  q->snew.c_cflag |= ISET_CFLAG;
1244  q->snew.c_lflag &=~ ICLEAR_LFLAG;
1245  cSmin = 1;
1246  q->snew.c_cc[VMIN] = cSmin;
1247  q->snew.c_cc[VTIME] = 1;
1248
1249  (void) cfsetospeed (&q->snew, ib);
1250  (void) cfsetispeed (&q->snew, ib);
1251
1252  /* Flush pending input.  */
1253  (void) tcflush (q->o, TCIFLUSH);
1254
1255#endif /* HAVE_POSIX_TERMIOS */
1256
1257#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1258  switch (tlocal)
1259    {
1260    case SET_CLOCAL:
1261      q->snew.c_cflag |= CLOCAL;
1262      break;
1263    case CLEAR_CLOCAL:
1264      q->snew.c_cflag &=~ CLOCAL;
1265      break;
1266    case IGNORE_CLOCAL:
1267      break;
1268    }
1269#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
1270
1271  if (! fsetterminfo (q->o, &q->snew))
1272    {
1273      ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
1274      return FALSE;
1275    }
1276
1277#ifdef TIOCSCTTY
1278  /* On BSD 4.4, make it our controlling terminal.  */
1279  (void) ioctl (q->o, TIOCSCTTY, 0);
1280#endif
1281
1282  if (ibaud != 0)
1283    q->ibaud = ibaud;
1284  else
1285    {
1286      size_t i;
1287
1288      q->ibaud = (long) 1200;
1289      for (i = 0; i < CBAUD_TABLE; i++)
1290	{
1291	  if (asSbaud_table[i].icode == ib
1292	      && asSbaud_table[i].ibaud != 0)
1293	    {
1294	      q->ibaud = asSbaud_table[i].ibaud;
1295	      break;
1296	    }
1297	}
1298
1299      DEBUG_MESSAGE1 (DEBUG_PORT,
1300		      "fsserial_open: Baud rate is %ld", q->ibaud);
1301    }
1302
1303  return TRUE;
1304}
1305
1306/* Open a standard input port.  The code alternates q->o between
1307   q->ord and q->owr as appropriate.  It is always q->ord before any
1308   call to fsblock.  */
1309
1310static boolean
1311fsstdin_open (qconn, ibaud, fwait, fuser)
1312     struct sconnection *qconn;
1313     long ibaud;
1314     boolean fwait;
1315     boolean fuser;
1316{
1317  struct ssysdep_conn *q;
1318
1319  q = (struct ssysdep_conn *) qconn->psysdep;
1320  q->ord = 0;
1321  q->owr = 1;
1322
1323  q->o = q->ord;
1324  if (! fsserial_open (qconn, ibaud, fwait, fuser, IGNORE_CLOCAL))
1325    return FALSE;
1326  q->iwr_flags = fcntl (q->owr, F_GETFL, 0);
1327  if (q->iwr_flags < 0)
1328    {
1329      ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
1330      return FALSE;
1331    }
1332  return TRUE;
1333}
1334
1335/* Open a modem port.  */
1336
1337static boolean
1338fsmodem_open (qconn, ibaud, fwait, fuser)
1339     struct sconnection *qconn;
1340     long ibaud;
1341     boolean fwait;
1342     boolean fuser;
1343{
1344  struct uuconf_modem_port *qm;
1345
1346  qm = &qconn->qport->uuconf_u.uuconf_smodem;
1347  if (ibaud == (long) 0)
1348    ibaud = qm->uuconf_ibaud;
1349
1350  if (! fsserial_open (qconn, ibaud, fwait, fuser,
1351		       fwait ? CLEAR_CLOCAL : SET_CLOCAL))
1352    return FALSE;
1353
1354  /* If we are waiting for carrier, then turn on hardware flow
1355     control.  We don't turn on hardware flow control when dialing
1356     out, because some modems don't assert the necessary signals until
1357     they see carrier.  Instead, we turn on hardware flow control in
1358     fsmodem_carrier.  */
1359  if (fwait
1360      && ! fsserial_hardflow (qconn, qm->uuconf_fhardflow))
1361    return FALSE;
1362
1363  return TRUE;
1364}
1365
1366/* Open a direct port.  */
1367
1368static boolean
1369fsdirect_open (qconn, ibaud, fwait, fuser)
1370     struct sconnection *qconn;
1371     long ibaud;
1372     boolean fwait;
1373     boolean fuser;
1374{
1375  struct uuconf_direct_port *qd;
1376
1377  qd = &qconn->qport->uuconf_u.uuconf_sdirect;
1378  if (ibaud == (long) 0)
1379    ibaud = qd->uuconf_ibaud;
1380  if (! fsserial_open (qconn, ibaud, fwait, fuser,
1381		       qd->uuconf_fcarrier ? CLEAR_CLOCAL : SET_CLOCAL))
1382    return FALSE;
1383
1384  /* Always turn on hardware flow control for a direct port when it is
1385     opened.  There is no other sensible time to turn it on.  */
1386  return fsserial_hardflow (qconn, qd->uuconf_fhardflow);
1387}
1388
1389/* Change the blocking status of the port.  We keep track of the
1390   current blocking status to avoid calling fcntl unnecessarily; fcntl
1391   turns out to be surprisingly expensive, at least on Ultrix.  */
1392
1393static boolean
1394fsblock (qs, fblock)
1395     struct ssysdep_conn *qs;
1396     boolean fblock;
1397{
1398  int iwant;
1399  int isys;
1400
1401  if (fblock)
1402    iwant = qs->iflags &~ (O_NDELAY | O_NONBLOCK);
1403  else
1404    iwant = qs->iflags | iSunblock;
1405
1406  if (iwant == qs->iflags)
1407    return TRUE;
1408
1409  isys = fcntl (qs->o, F_SETFL, iwant);
1410  if (isys < 0)
1411    {
1412#if O_NONBLOCK != 0
1413      if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL)
1414	{
1415	  iSunblock = O_NONBLOCK;
1416	  iwant = qs->iflags | O_NONBLOCK;
1417	  isys = fcntl (qs->o, F_SETFL, iwant);
1418	}
1419#endif
1420      if (isys < 0)
1421	{
1422	  ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
1423	  return FALSE;
1424	}
1425    }
1426
1427  qs->iflags = iwant;
1428
1429  if (qs->iwr_flags >= 0 && qs->ord != qs->owr)
1430    {
1431      if (fblock)
1432	iwant = qs->iwr_flags &~ (O_NDELAY | O_NONBLOCK);
1433      else
1434	iwant = qs->iwr_flags | iSunblock;
1435
1436      isys = fcntl (qs->owr, F_SETFL, iwant);
1437      if (isys < 0)
1438	{
1439#if O_NONBLOCK != 0
1440	  if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL)
1441	    {
1442	      iSunblock = O_NONBLOCK;
1443	      iwant = qs->iwr_flags | O_NONBLOCK;
1444	      isys = fcntl (qs->owr, F_SETFL, iwant);
1445	    }
1446#endif
1447	  if (isys < 0)
1448	    {
1449	      ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
1450	      return FALSE;
1451	    }
1452	}
1453
1454      qs->iwr_flags = iwant;
1455    }
1456
1457  return TRUE;
1458}
1459
1460/* Close a serial port.  */
1461
1462static boolean
1463fsserial_close (q)
1464     struct ssysdep_conn *q;
1465{
1466  if (q->o >= 0)
1467    {
1468      /* Use a 30 second timeout to avoid hanging while draining
1469	 output.  */
1470      if (q->fterminal)
1471	{
1472	  fSalarm = FALSE;
1473
1474	  if (fsysdep_catch ())
1475	    {
1476	      usysdep_start_catch ();
1477	      usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
1478	      (void) alarm (30);
1479
1480	      (void) fsetterminfodrain (q->o, &q->sorig);
1481	    }
1482
1483	  usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
1484	  (void) alarm (0);
1485	  usysdep_end_catch ();
1486
1487	  /* If we timed out, use the non draining call.  Hopefully
1488	     this can't hang.  */
1489	  if (fSalarm)
1490	    (void) fsetterminfo (q->o, &q->sorig);
1491	}
1492
1493#ifdef TIOCNOTTY
1494      /* We don't want this as our controlling terminal any more, so
1495	 get rid of it.  This is necessary because we don't want to
1496	 open /dev/tty, since that can confuse the serial port locking
1497	 on some computers.  */
1498      (void) ioctl (q->o, TIOCNOTTY, (char *) NULL);
1499#endif
1500
1501      (void) close (q->o);
1502      q->o = -1;
1503
1504      /* Sleep to give the terminal a chance to settle, in case we are
1505	 about to call out again.  */
1506      sleep (2);
1507    }
1508
1509  return TRUE;
1510}
1511
1512/* Close a stdin port.  */
1513
1514/*ARGSUSED*/
1515static boolean
1516fsstdin_close (qconn, puuconf, qdialer, fsuccess)
1517     struct sconnection *qconn;
1518     pointer puuconf ATTRIBUTE_UNUSED;
1519     struct uuconf_dialer *qdialer ATTRIBUTE_UNUSED;
1520     boolean fsuccess ATTRIBUTE_UNUSED;
1521{
1522  struct ssysdep_conn *qsysdep;
1523
1524  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
1525  (void) close (qsysdep->owr);
1526  (void) close (2);
1527  qsysdep->o = qsysdep->ord;
1528  return fsserial_close (qsysdep);
1529}
1530
1531/* Close a modem port.  */
1532
1533static boolean
1534fsmodem_close (qconn, puuconf, qdialer, fsuccess)
1535     struct sconnection *qconn;
1536     pointer puuconf;
1537     struct uuconf_dialer *qdialer;
1538     boolean fsuccess;
1539{
1540  struct ssysdep_conn *qsysdep;
1541  boolean fret;
1542  struct uuconf_dialer sdialer;
1543  const struct uuconf_chat *qchat;
1544
1545  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
1546
1547  fret = TRUE;
1548
1549  /* Figure out the dialer so that we can run the complete or abort
1550     chat scripts.  */
1551  if (qdialer == NULL)
1552    {
1553      if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
1554	{
1555	  const char *zdialer;
1556	  int iuuconf;
1557
1558	  zdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0];
1559	  iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer);
1560	  if (iuuconf == UUCONF_SUCCESS)
1561	    qdialer = &sdialer;
1562	  else
1563	    {
1564	      ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
1565	      fret = FALSE;
1566	    }
1567	}
1568      else
1569	qdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
1570    }
1571
1572  /* Get the complete or abort chat script to use.  */
1573  qchat = NULL;
1574  if (qdialer != NULL)
1575    {
1576      if (fsuccess)
1577	qchat = &qdialer->uuconf_scomplete;
1578      else
1579	qchat = &qdialer->uuconf_sabort;
1580    }
1581
1582  if (qchat != NULL
1583      && (qchat->uuconf_pzprogram != NULL
1584	  || qchat->uuconf_pzchat != NULL))
1585    {
1586      boolean fsighup_ignored;
1587      HELD_SIG_MASK smask;
1588      int i;
1589      sig_atomic_t afhold[INDEXSIG_COUNT];
1590
1591      /* We're no longer interested in carrier.  */
1592      (void) fsmodem_carrier (qconn, FALSE);
1593
1594      /* The port I/O routines check whether any signal has been
1595	 received, and abort if one has.  While we are closing down
1596	 the modem, we don't care if we received a signal in the past,
1597	 but we do care if we receive a new signal (otherwise it would
1598	 be difficult to kill a uucico which was closing down a
1599	 modem).  We never care if we get SIGHUP at this point.  So we
1600	 turn off SIGHUP, remember what signals we've already seen,
1601	 and clear our notion of what signals we've seen.  We have to
1602	 block the signals while we remember and clear the array,
1603	 since we might otherwise miss a signal which occurred between
1604	 the copy and the clear (old systems can't block signals; they
1605	 will just have to suffer the race).  */
1606      usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored);
1607      smask = isblocksigs ();
1608      for (i = 0; i < INDEXSIG_COUNT; i++)
1609	{
1610	  afhold[i] = afSignal[i];
1611	  afSignal[i] = FALSE;
1612	}
1613      usunblocksigs (smask);
1614
1615      if (! fchat (qconn, puuconf, qchat, (const struct uuconf_system *) NULL,
1616		   (const struct uuconf_dialer *) NULL, (const char *) NULL,
1617		   FALSE, qconn->qport->uuconf_zname,
1618		   qsysdep->ibaud))
1619	fret = FALSE;
1620
1621      /* Restore the old signal array and the SIGHUP handler.  It is
1622	 not necessary to block signals here, since all we are doing
1623	 is exactly what the signal handler itself would do if the
1624	 signal occurred.  */
1625      for (i = 0; i < INDEXSIG_COUNT; i++)
1626	if (afhold[i])
1627	  afSignal[i] = TRUE;
1628      if (! fsighup_ignored)
1629	usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
1630    }
1631
1632  if (qdialer != NULL
1633      && qdialer == &sdialer)
1634    (void) uuconf_dialer_free (puuconf, &sdialer);
1635
1636#if ! HAVE_RESET_BUG
1637  /* Reset the terminal to make sure we drop DTR.  It should be
1638     dropped when we close the descriptor, but that doesn't seem to
1639     happen on some systems.  Use a 30 second timeout to avoid hanging
1640     while draining output.  */
1641  if (qsysdep->fterminal)
1642    {
1643#if HAVE_BSD_TTY
1644      qsysdep->snew.stty.sg_ispeed = B0;
1645      qsysdep->snew.stty.sg_ospeed = B0;
1646#endif
1647#if HAVE_SYSV_TERMIO
1648      qsysdep->snew.c_cflag = (qsysdep->snew.c_cflag &~ CBAUD) | B0;
1649#endif
1650#if HAVE_POSIX_TERMIOS
1651      (void) cfsetospeed (&qsysdep->snew, B0);
1652#endif
1653
1654      fSalarm = FALSE;
1655
1656      if (fsysdep_catch ())
1657	{
1658	  usysdep_start_catch ();
1659	  usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
1660	  (void) alarm (30);
1661
1662	  (void) fsetterminfodrain (qsysdep->o, &qsysdep->snew);
1663	}
1664
1665      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
1666      (void) alarm (0);
1667      usysdep_end_catch ();
1668
1669      /* Let the port settle.  */
1670      sleep (2);
1671    }
1672#endif /* ! HAVE_RESET_BUG */
1673
1674  if (! fsserial_close (qsysdep))
1675    fret = FALSE;
1676
1677  return fret;
1678}
1679
1680/* Close a direct port.  */
1681
1682/*ARGSUSED*/
1683static boolean
1684fsdirect_close (qconn, puuconf, qdialer, fsuccess)
1685     struct sconnection *qconn;
1686     pointer puuconf ATTRIBUTE_UNUSED;
1687     struct uuconf_dialer *qdialer ATTRIBUTE_UNUSED;
1688     boolean fsuccess ATTRIBUTE_UNUSED;
1689{
1690  return fsserial_close ((struct ssysdep_conn *) qconn->psysdep);
1691}
1692
1693/* Begin dialing out on a modem port.  This opens the dialer device if
1694   there is one.  */
1695
1696boolean
1697fsysdep_modem_begin_dial (qconn, qdial)
1698     struct sconnection *qconn;
1699     struct uuconf_dialer *qdial;
1700{
1701  struct ssysdep_conn *qsysdep;
1702  const char *z;
1703
1704  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
1705
1706#ifdef TIOCMODEM
1707  /* If we can tell the modem to obey modem control, do so.  */
1708  {
1709    int iperm;
1710
1711    iperm = 0;
1712    (void) ioctl (qsysdep->o, TIOCMODEM, &iperm);
1713  }
1714#endif /* TIOCMODEM */
1715
1716  /* If we supposed to toggle DTR, do so.  */
1717
1718  if (qdial->uuconf_fdtr_toggle)
1719    {
1720#ifdef TIOCCDTR
1721      (void) ioctl (qsysdep->o, TIOCCDTR, 0);
1722      sleep (2);
1723      (void) ioctl (qsysdep->o, TIOCSDTR, 0);
1724#else /* ! defined (TIOCCDTR) */
1725      if (qsysdep->fterminal)
1726	{
1727	  sterminal sbaud;
1728
1729	  sbaud = qsysdep->snew;
1730
1731#if HAVE_BSD_TTY
1732	  sbaud.stty.sg_ispeed = B0;
1733	  sbaud.stty.sg_ospeed = B0;
1734#endif
1735#if HAVE_SYSV_TERMIO
1736	  sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
1737#endif
1738#if HAVE_POSIX_TERMIOS
1739	  (void) cfsetospeed (&sbaud, B0);
1740#endif
1741
1742	  (void) fsetterminfodrain (qsysdep->o, &sbaud);
1743	  sleep (2);
1744	  (void) fsetterminfo (qsysdep->o, &qsysdep->snew);
1745	}
1746#endif /* ! defined (TIOCCDTR) */
1747
1748      if (qdial->uuconf_fdtr_toggle_wait)
1749	sleep (2);
1750    }
1751
1752  if (! fsmodem_carrier (qconn, FALSE))
1753    return FALSE;
1754
1755  /* Open the dial device if there is one.  */
1756  z = qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device;
1757  if (z != NULL)
1758    {
1759      char *zfree;
1760      int o;
1761
1762      qsysdep->ohold = qsysdep->o;
1763
1764      zfree = NULL;
1765      if (*z != '/')
1766	{
1767	  zfree = zbufalc (sizeof "/dev/" + strlen (z));
1768	  sprintf (zfree, "/dev/%s", z);
1769	  z = zfree;
1770	}
1771
1772      o = open ((char *) z, O_RDWR | O_NOCTTY);
1773      if (o < 0)
1774	{
1775	  ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
1776	  ubuffree (zfree);
1777	  return FALSE;
1778	}
1779      ubuffree (zfree);
1780
1781      if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
1782	{
1783	  ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
1784	  (void) close (o);
1785	  return FALSE;
1786	}
1787
1788      qsysdep->o = o;
1789    }
1790
1791  return TRUE;
1792}
1793
1794/* Tell the port to require or not require carrier.  On BSD this uses
1795   TIOCCAR and TIOCNCAR, which I assume are generally supported (it
1796   can also use the LNOMDM bit supported by IS68K Unix).  On System V
1797   it resets or sets CLOCAL.  We only require carrier if the port
1798   supports it.  This will only be called with fcarrier TRUE if the
1799   dialer supports carrier.  */
1800
1801static boolean
1802fsmodem_carrier (qconn, fcarrier)
1803     struct sconnection *qconn;
1804     boolean fcarrier;
1805{
1806  register struct ssysdep_conn *q;
1807  struct uuconf_modem_port *qm;
1808
1809  q = (struct ssysdep_conn *) qconn->psysdep;
1810
1811  if (! q->fterminal)
1812    return TRUE;
1813
1814  qm = &qconn->qport->uuconf_u.uuconf_smodem;
1815  if (fcarrier)
1816    {
1817      if (qm->uuconf_fcarrier)
1818	{
1819#ifdef TIOCCAR
1820	  /* Tell the modem to pay attention to carrier.  */
1821	  if (ioctl (q->o, TIOCCAR, 0) < 0)
1822	    {
1823	      ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno));
1824	      return FALSE;
1825	    }
1826#endif /* TIOCCAR */
1827
1828#if HAVE_BSD_TTY
1829#ifdef LNOMDM
1830	  /* IS68K Unix uses a local LNOMDM bit.  */
1831	  {
1832	    int iparam;
1833
1834	    iparam = LNOMDM;
1835	    if (ioctl (q->o, TIOCLBIC, &iparam) < 0)
1836	      {
1837		ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s",
1838		      strerror (errno));
1839		return FALSE;
1840	      }
1841	  }
1842#endif /* LNOMDM */
1843#endif /* HAVE_BSD_TTY */
1844
1845#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1846	  /* Put the modem into nonlocal mode.  */
1847	  q->snew.c_cflag &=~ CLOCAL;
1848	  if (! fsetterminfo (q->o, &q->snew))
1849	    {
1850	      ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno));
1851	      return FALSE;
1852	    }
1853#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
1854	}
1855
1856      /* Turn on hardware flow control after turning on carrier.  We
1857	 don't do it until now because some modems don't assert the
1858	 right signals until they see carrier.  */
1859      if (! fsserial_hardflow (qconn, qm->uuconf_fhardflow))
1860	return FALSE;
1861    }
1862  else
1863    {
1864      /* Turn off any hardware flow control before turning off
1865	 carrier.  */
1866      if (! fsserial_hardflow (qconn, FALSE))
1867	return FALSE;
1868
1869#ifdef TIOCNCAR
1870      /* Tell the modem to ignore carrier.  */
1871      if (ioctl (q->o, TIOCNCAR, 0) < 0)
1872	{
1873	  ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno));
1874	  return FALSE;
1875	}
1876#endif /* TIOCNCAR */
1877
1878#if HAVE_BSD_TTY
1879#ifdef LNOMDM
1880      /* IS68K Unix uses a local LNOMDM bit.  */
1881      {
1882	int iparam;
1883
1884	iparam = LNOMDM;
1885	if (ioctl (q->o, TIOCLBIS, &iparam) < 0)
1886	  {
1887	    ulog (LOG_ERROR, "ioctl (TIOCLBIS, LNOMDM): %s",
1888		  strerror (errno));
1889	    return FALSE;
1890	  }
1891      }
1892#endif /* LNOMDM */
1893#endif /* HAVE_BSD_TTY */
1894
1895#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1896      /* Put the modem into local mode (ignore carrier) to start the chat
1897	 script.  */
1898      q->snew.c_cflag |= CLOCAL;
1899      if (! fsetterminfo (q->o, &q->snew))
1900	{
1901	  ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno));
1902	  return FALSE;
1903	}
1904
1905#if HAVE_CLOCAL_BUG
1906      /* On SCO and AT&T UNIX PC you have to reopen the port.  */
1907      {
1908	int onew;
1909
1910	onew = open (q->zdevice, O_RDWR);
1911	if (onew < 0)
1912	  {
1913	    ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno));
1914	    return FALSE;
1915	  }
1916
1917	if (fcntl (onew, F_SETFD,
1918		   fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
1919	  {
1920	    ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
1921	    (void) close (onew);
1922	    return FALSE;
1923	  }
1924
1925	(void) close (q->o);
1926	q->o = onew;
1927      }
1928#endif /* HAVE_CLOCAL_BUG */
1929
1930#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
1931    }
1932
1933  return TRUE;
1934}
1935
1936/* Tell the port to use hardware flow control.  There is no standard
1937   mechanism for controlling this.  This implementation supports
1938   CRTSCTS and CRTSXOFF on SunOS/Solaris, RTS/CTSFLOW on 386(ish)
1939   unix, CTSCD on the 3b1, CCTS_OFLOW/CRTS_IFLOW on BSDI,
1940   TXADDCD/TXDELCD on AIX, IRTS on NCR Tower, and TCGETX/TCSETX on
1941   HP/UX.  If you know how to do it on other systems, please implement
1942   it and send me the patches.  */
1943
1944static boolean
1945fsserial_hardflow (qconn, fhardflow)
1946     struct sconnection *qconn;
1947     boolean fhardflow;
1948{
1949  register struct ssysdep_conn *q;
1950
1951  q = (struct ssysdep_conn *) qconn->psysdep;
1952
1953  if (! q->fterminal)
1954    return TRUE;
1955
1956  /* Don't do anything if we don't know what to do.  */
1957#if HAVE_BSD_TTY
1958#define HAVE_HARDFLOW 0
1959#endif
1960#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1961#if ! HAVE_TXADDCD
1962#ifndef CRTSFL
1963#ifndef CRTSCTS
1964#ifndef CTSCD
1965#ifndef CCTS_OFLOW
1966#ifndef IRTS
1967#define HAVE_HARDFLOW 0
1968#endif
1969#endif
1970#endif
1971#endif
1972#endif
1973#endif
1974#endif
1975
1976#ifndef HAVE_HARDFLOW
1977#define HAVE_HARDFLOW 1
1978#endif
1979
1980#if HAVE_HARDFLOW
1981  if (fhardflow)
1982    {
1983#if HAVE_TXADDCD
1984      /* The return value does not reliably indicate whether this
1985	 actually succeeded.  */
1986      (void) ioctl (q->o, TXADDCD, "rts");
1987#else /* ! HAVE_TXADDCD */
1988#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1989#ifdef CRTSFL
1990      q->snew.c_cflag |= CRTSFL;
1991      q->snew.c_cflag &=~ (RTSFLOW | CTSFLOW);
1992#endif /* defined (CRTSFL) */
1993#ifdef CRTSCTS
1994      q->snew.c_cflag |= CRTSCTS;
1995#endif /* defined (CRTSCTS) */
1996#ifdef CRTSXOFF
1997      q->snew.c_cflag |= CRTSXOFF;
1998#endif /* defined (CRTSXOFF) */
1999#ifdef CTSCD
2000      q->snew.c_cflag |= CTSCD;
2001#endif /* defined (CTSCD) */
2002#ifdef CCTS_OFLOW
2003      q->snew.c_cflag |= CCTS_OFLOW | CRTS_IFLOW;
2004#endif
2005#ifdef IRTS
2006      q->snew.c_iflag |= IRTS;
2007#endif
2008#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
2009      if (! fsetterminfo (q->o, &q->snew))
2010	{
2011	  ulog (LOG_ERROR, "Can't enable hardware flow control: %s",
2012		strerror (errno));
2013	  return FALSE;
2014	}
2015#if HAVE_SYS_TERMIOX
2016#ifdef TCGETX
2017      {
2018	struct termiox tx;
2019
2020	if (ioctl (q->o, TCGETX, &tx) < 0)
2021	  {
2022	    ulog (LOG_ERROR,
2023		  "Can't enable hardware flow control: ioctl (TCGETX): %s",
2024		  strerror (errno));
2025	    return FALSE;
2026	  }
2027	tx.x_hflag |= RTSXOFF | CTSXON;
2028	if (ioctl (q->o, TCSETX, &tx) < 0)
2029	  {
2030	    ulog (LOG_ERROR,
2031		  "Can't enable hardware flow control: ioctl (TCSETX): %s",
2032		  strerror (errno));
2033	    return FALSE;
2034	  }
2035      }
2036#endif /* TCGETX */
2037#endif /* HAVE_SYS_TERMIOX */
2038#endif /* ! HAVE_TXADDCD */
2039    }
2040  else
2041    {
2042#if HAVE_TXADDCD
2043      /* The return value does not reliably indicate whether this
2044	 actually succeeded.  */
2045      (void) ioctl (q->o, TXDELCD, "rts");
2046#else /* ! HAVE_TXADDCD */
2047#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
2048#ifdef CRTSFL
2049      q->snew.c_cflag &=~ CRTSFL;
2050      q->snew.c_cflag &=~ (RTSFLOW | CTSFLOW);
2051#endif /* defined (CRTSFL) */
2052#ifdef CRTSCTS
2053      q->snew.c_cflag &=~ CRTSCTS;
2054#endif /* defined (CRTSCTS) */
2055#ifdef CRTSXOFF
2056      q->snew.c_cflag &=~ CRTSXOFF;
2057#endif /* defined (CRTSXOFF) */
2058#ifdef CTSCD
2059      q->snew.c_cflag &=~ CTSCD;
2060#endif /* defined (CTSCD) */
2061#ifdef CCTS_OFLOW
2062      q->snew.c_cflag &=~ (CCTS_OFLOW | CRTS_IFLOW);
2063#endif
2064#ifdef IRTS
2065      q->snew.c_iflag &=~ IRTS;
2066#endif
2067#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
2068      if (! fsetterminfo (q->o, &q->snew))
2069	{
2070	  ulog (LOG_ERROR, "Can't disable hardware flow control: %s",
2071		strerror (errno));
2072	  return FALSE;
2073	}
2074#if HAVE_SYS_TERMIOX
2075#ifdef TCGETX
2076      {
2077	struct termiox tx;
2078
2079	if (ioctl (q->o, TCGETX, &tx) < 0)
2080	  {
2081	    ulog (LOG_ERROR,
2082		  "Can't disable hardware flow control: ioctl (TCGETX): %s",
2083		  strerror (errno));
2084	    return FALSE;
2085	  }
2086	tx.x_hflag &=~ (RTSXOFF | CTSXON);
2087	if (ioctl (q->o, TCSETX, &tx) < 0)
2088	  {
2089	    ulog (LOG_ERROR,
2090		  "Can't disable hardware flow control: ioctl (TCSETX): %s",
2091		  strerror (errno));
2092	    return FALSE;
2093	  }
2094      }
2095#endif /* TCGETX */
2096#endif /* HAVE_SYS_TERMIOX */
2097#endif /* ! HAVE_TXADDCD */
2098    }
2099#endif /* HAVE_HARDFLOW */
2100
2101  return TRUE;
2102}
2103
2104/* Finish dialing out on a modem by closing any dialer device and waiting
2105   for carrier.  */
2106
2107boolean
2108fsysdep_modem_end_dial (qconn, qdial)
2109     struct sconnection *qconn;
2110     struct uuconf_dialer *qdial;
2111{
2112  struct ssysdep_conn *q;
2113
2114  q = (struct ssysdep_conn *) qconn->psysdep;
2115
2116  if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL)
2117    {
2118      (void) close (q->o);
2119      q->o = q->ohold;
2120    }
2121
2122  if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier
2123      && qdial->uuconf_fcarrier)
2124    {
2125      /* Tell the port that we need carrier.  */
2126      if (! fsmodem_carrier (qconn, TRUE))
2127	return FALSE;
2128
2129#ifdef TIOCWONLINE
2130
2131      /* We know how to wait for carrier, so do so.  */
2132
2133      /* If we already got a signal, just quit now.  */
2134      if (FGOT_QUIT_SIGNAL ())
2135	return FALSE;
2136
2137      /* This bit of code handles signals just like fsysdep_conn_read
2138	 does.  See that function for a longer explanation.  */
2139
2140      /* Use fsysdep_catch to handle a longjmp from the signal
2141	 handler.  */
2142
2143      fSalarm = FALSE;
2144
2145      if (fsysdep_catch ())
2146	{
2147	  /* Start catching SIGALRM; normally we ignore it.  */
2148	  usysdep_start_catch ();
2149	  usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
2150	  (void) alarm (qdial->uuconf_ccarrier_wait);
2151
2152	  /* We really don't care if we get an error, since that will
2153	     probably just mean that TIOCWONLINE isn't supported in
2154	     which case there's nothing we can do anyhow.  If we get
2155	     SIGINT we want to keep waiting for carrier, because
2156	     SIGINT just means don't start any new sessions.  We don't
2157	     handle SIGINT correctly if we do a longjmp in the signal
2158	     handler; too bad.  */
2159	  while (ioctl (q->o, TIOCWONLINE, 0) < 0
2160		 && errno == EINTR)
2161	    {
2162	      /* Log the signal.  */
2163	      ulog (LOG_ERROR, (const char *) NULL);
2164	      if (FGOT_QUIT_SIGNAL () || fSalarm)
2165		break;
2166	    }
2167	}
2168
2169      /* Turn off the pending SIGALRM and ignore SIGALARM again.  */
2170      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
2171      (void) alarm (0);
2172      usysdep_end_catch ();
2173
2174      /* If we got a random signal, just return FALSE.  */
2175      if (FGOT_QUIT_SIGNAL ())
2176	return FALSE;
2177
2178      /* If we timed out, give an error.  */
2179      if (fSalarm)
2180	{
2181	  ulog (LOG_ERROR, "Timed out waiting for carrier");
2182	  return FALSE;
2183	}
2184
2185#else /* ! defined (TIOCWONLINE) */
2186
2187      /* Try to open the port again without using O_NDELAY.  In
2188	 principle, the open should delay until carrier is available.
2189	 This may not work on some systems, so we just ignore any
2190	 errors.  */
2191      {
2192	int onew;
2193
2194	onew = open (q->zdevice, O_RDWR);
2195	if (onew >= 0)
2196	  {
2197	    boolean fbad;
2198	    int iflags;
2199
2200	    fbad = FALSE;
2201
2202	    if (fcntl (onew, F_SETFD,
2203		       fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
2204	      fbad = TRUE;
2205
2206	    if (! fbad)
2207	      {
2208		iflags = fcntl (onew, F_GETFL, 0);
2209		if (iflags < 0
2210		    || ! fsetterminfo (onew, &q->snew))
2211		  fbad = TRUE;
2212	      }
2213
2214	    if (fbad)
2215	      (void) close (onew);
2216	    else
2217	      {
2218		(void) close (q->o);
2219		q->o = onew;
2220		q->iflags = iflags;
2221#if HAVE_TIOCSINUSE
2222		(void) ioctl (onew, TIOCSINUSE, 0);
2223#endif
2224	      }
2225	  }
2226      }
2227
2228#endif /* ! defined (TIOCWONLINE) */
2229    }
2230
2231  return TRUE;
2232}
2233
2234/* Read data from a connection, with a timeout.  This routine handles
2235   all types of connections, including TLI.
2236
2237   This function should return when we have read cmin characters or
2238   the timeout has occurred.  We have to work a bit to get Unix to do
2239   this efficiently on a terminal.  The simple implementation
2240   schedules a SIGALRM signal and then calls read; if there is a
2241   single character available, the call to read will return
2242   immediately, so there must be a loop which terminates when the
2243   SIGALRM is delivered or the correct number of characters has been
2244   read.  This can be very inefficient with a fast CPU or a low baud
2245   rate (or both!), since each call to read may return only one or two
2246   characters.
2247
2248   Under POSIX or System V, we can specify a minimum number of
2249   characters to read, so there is no serious trouble.
2250
2251   Under BSD, we figure out how many characters we have left to read,
2252   how long it will take for them to arrive at the current baud rate,
2253   and sleep that long.
2254
2255   Doing this with a timeout and avoiding all possible race conditions
2256   get very hairy, though.  Basically, we're going to schedule a
2257   SIGALRM for when the timeout expires.  I don't really want to do a
2258   longjmp in the SIGALRM handler, though, because that may lose data.
2259   Therefore, I have the signal handler set a variable.  However, this
2260   means that there will be a span of time between the time the code
2261   checks the variable and the time it calls the read system call; if
2262   the SIGALRM occurs during that time, the read might hang forever.
2263   To avoid this, the SIGALRM handler not only sets a global variable,
2264   it also schedules another SIGALRM for one second in the future
2265   (POSIX specifies that a signal handler is permitted to safely call
2266   alarm).  To avoid getting a continual sequence of SIGALRM
2267   interrupts, we change the signal handler to ignore SIGALRM when
2268   we're about to exit the function.  This means that every time we
2269   execute fsysdep_conn_read we make at least five system calls.  It's
2270   the best I've been able to come up with, though.
2271
2272   When fsysdep_conn_read finishes, there will be no SIGALRM scheduled
2273   and SIGALRM will be ignored.  */
2274
2275boolean
2276fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
2277     struct sconnection *qconn;
2278     char *zbuf;
2279     size_t *pclen;
2280     size_t cmin;
2281     int ctimeout;
2282     boolean freport;
2283{
2284  CATCH_PROTECT size_t cwant;
2285  boolean fret;
2286  register struct ssysdep_conn * const q
2287    = (struct ssysdep_conn *) qconn->psysdep;
2288  int cwouldblock;
2289
2290  cwant = *pclen;
2291  *pclen = 0;
2292
2293  /* Guard against a bad timeout.  We return TRUE when a timeout
2294     expires.  It is possible to get a negative timeout here because
2295     the calling code does not check user supplied timeouts for
2296     plausibility.  */
2297  if (ctimeout <= 0)
2298    return TRUE;
2299
2300  /* We want to do a blocking read.  */
2301  if (! fsblock (q, TRUE))
2302    return FALSE;
2303
2304  fSalarm = FALSE;
2305
2306  /* We're going to set up an alarm signal to last for the entire
2307     read.  If the read system call cannot be interrupted, the signal
2308     handler will do a longjmp causing fsysdep_catch (a macro) to
2309     return FALSE.  We handle that here.  If read can be interrupted,
2310     fsysdep_catch will be defined to TRUE.  */
2311  if (fsysdep_catch ())
2312    {
2313      /* Prepare to catch SIGALRM and schedule the signal.  */
2314      usysdep_start_catch ();
2315      usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
2316      alarm (ctimeout);
2317    }
2318  else
2319    {
2320      /* We caught a signal.  We don't actually have to do anything,
2321	 as all the appropriate checks are made at the start of the
2322	 following loop.  */
2323    }
2324
2325  fret = FALSE;
2326
2327  cwouldblock = 0;
2328  while (TRUE)
2329    {
2330      int cgot;
2331
2332#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
2333      /* If we can tell the terminal not to return until we have a
2334	 certain number of characters, do so.  */
2335      if (q->fterminal)
2336	{
2337	  int csetmin;
2338
2339	  /* I'm not that confident about setting MIN to values larger
2340	     than 127, although up to 255 would probably work.  */
2341	  if (cmin < 127)
2342	    csetmin = cmin;
2343	  else
2344	    csetmin = 127;
2345
2346	  if (csetmin != cSmin)
2347	    {
2348	      q->snew.c_cc[VMIN] = csetmin;
2349	      while (! fsetterminfo (q->o, &q->snew))
2350		{
2351		  if (errno != EINTR
2352		      || FGOT_QUIT_SIGNAL ())
2353		    {
2354		      int ierr;
2355
2356		      /* We turn off the signal before reporting the
2357			 error to minimize any problems with
2358			 interrupted system calls.  */
2359		      ierr = errno;
2360		      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
2361		      alarm (0);
2362		      usysdep_end_catch ();
2363		      ulog (LOG_ERROR, "Can't set MIN for terminal: %s",
2364			    strerror (ierr));
2365		      return FALSE;
2366		    }
2367
2368		  if (fSalarm)
2369		    {
2370		      ulog (LOG_ERROR,
2371			    "Timed out when setting MIN to %d; retrying",
2372			    csetmin);
2373		      fSalarm = FALSE;
2374		      alarm (ctimeout);
2375		    }
2376		}
2377	      cSmin = csetmin;
2378	    }
2379	}
2380#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
2381
2382      /* If we've received a signal, get out now.  */
2383      if (FGOT_QUIT_SIGNAL ())
2384	break;
2385
2386      /* If we've already gotten a SIGALRM, get out with whatever
2387	 we've accumulated.  */
2388      if (fSalarm)
2389	{
2390	  fret = TRUE;
2391	  break;
2392	}
2393
2394      /* Right here is the race condition which we avoid by having the
2395	 SIGALRM handler schedule another SIGALRM.  */
2396#if HAVE_TLI
2397      if (q->ftli)
2398	{
2399	  int iflags;
2400
2401	  cgot = t_rcv (q->o, zbuf, cwant, &iflags);
2402	  if (cgot < 0 && t_errno != TSYSERR)
2403	    {
2404	      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
2405	      alarm (0);
2406	      usysdep_end_catch ();
2407
2408	      if (freport)
2409		ulog (LOG_ERROR, "t_rcv: %s",
2410		      (t_errno >= 0 && t_errno < t_nerr
2411		       ? t_errlist[t_errno]
2412		       : "unknown TLI error"));
2413
2414	      return FALSE;
2415	    }
2416	}
2417      else
2418#endif
2419	cgot = read (q->o, zbuf, cwant);
2420
2421      /* If the read returned an error, check for signals.  */
2422      if (cgot < 0)
2423	{
2424	  if (errno == EINTR)
2425	    {
2426	      /* Log the signal.  */
2427	      ulog (LOG_ERROR, (const char *) NULL);
2428	    }
2429	  if (fSalarm)
2430	    {
2431	      fret = TRUE;
2432	      break;
2433	    }
2434	  if (FGOT_QUIT_SIGNAL ())
2435	    break;
2436	}
2437
2438      /* If read returned an error, get out.  We just ignore EINTR
2439	 here, since it must be from some signal we don't care about.
2440	 If the read returned 0 then the line must have been hung up
2441	 (normally we would have received SIGHUP, but we can't count
2442	 on that).  We turn off the signals before calling ulog to
2443	 reduce problems with interrupted system calls.  */
2444      if (cgot > 0)
2445	cwouldblock = 0;
2446      else
2447	{
2448	  if (cgot < 0 && errno == EINTR)
2449	    cgot = 0;
2450	  else if (cgot < 0
2451		   && (errno == EAGAIN || errno == EWOULDBLOCK)
2452		   && cwouldblock < 2)
2453	    {
2454	      /* Incomprehensibly, on some systems the read will
2455		 return EWOULDBLOCK even though the descriptor has
2456		 been set to blocking mode.  We permit the read call
2457		 to do this twice in a row, and then error out.  We
2458		 don't want to permit an arbitrary number of
2459		 EWOULDBLOCK errors, since that could hang us up
2460		 indefinitely.  */
2461	      ++cwouldblock;
2462	      cgot = 0;
2463	    }
2464	  else
2465	    {
2466	      int ierr;
2467
2468	      ierr = errno;
2469
2470	      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
2471	      alarm (0);
2472	      usysdep_end_catch ();
2473
2474	      if (freport)
2475		{
2476		  if (cgot == 0)
2477		    ulog (LOG_ERROR, "Line disconnected");
2478		  else
2479		    ulog (LOG_ERROR, "read: %s", strerror (ierr));
2480		}
2481
2482	      return FALSE;
2483	    }
2484	}
2485
2486      cwant -= cgot;
2487      if ((size_t) cgot >= cmin)
2488	cmin = 0;
2489      else
2490	cmin -= cgot;
2491      zbuf += cgot;
2492      *pclen += cgot;
2493
2494      /* If we have enough data, get out now.  */
2495      if (cmin == 0)
2496	{
2497	  fret = TRUE;
2498	  break;
2499	}
2500
2501#if HAVE_BSD_TTY
2502      /* We still want more data, so sleep long enough for the rest of
2503	 it to arrive.  We don't this for System V or POSIX because
2504	 setting MIN is good enough (we can't sleep longer than it
2505	 takes to get MAX_INPUT characters anyhow).
2506
2507	 The baud rate is approximately 10 times the number of
2508	 characters which will arrive in one second, so the number of
2509	 milliseconds to sleep ==
2510	 characters * (milliseconds / character) ==
2511	 characters * (1000 * (seconds / character)) ==
2512	 characters * (1000 * (1 / (baud / 10))) ==
2513	 characters * (10000 / baud)
2514
2515	 We arbitrarily reduce the sleep amount by 10 milliseconds to
2516	 attempt to account for the amount of time it takes to set up
2517	 the sleep.  This is how long it takes to get half a character
2518	 at 19200 baud.  We then don't bother to sleep for less than
2519	 10 milliseconds.  We don't sleep if the read was interrupted.
2520
2521	 We use select to sleep.  It would be easy to use poll as
2522	 well, but it's unlikely that any system with BSD ttys would
2523	 have poll but not select.  Using select avoids hassles with
2524	 the pending SIGALRM; if it hits the select will be
2525	 interrupted, and otherwise the select will not affect it.  */
2526
2527#if ! HAVE_SELECT
2528 #error This code requires select; feel free to extend it
2529#endif
2530
2531      if (q->fterminal && cmin > 1 && cgot > 0)
2532	{
2533	  int csleepchars;
2534	  int isleep;
2535
2536	  /* We don't try to read all the way up to MAX_INPUT,
2537	     since that might drop a character.  */
2538	  if (cmin <= MAX_INPUT - 10)
2539	    csleepchars = cmin;
2540	  else
2541	    csleepchars = MAX_INPUT - 10;
2542
2543	  isleep = (int) (((long) csleepchars * 10000L) / q->ibaud);
2544	  isleep -= 10;
2545
2546	  if (isleep > 10)
2547	    {
2548	      struct timeval s;
2549
2550	      s.tv_sec = isleep / 1000;
2551	      s.tv_usec = (isleep % 1000) * 1000;
2552
2553	      /* Some versions of select take a pointer to an int,
2554		 while some take a pointer to an fd_set.  I just cast
2555		 the arguments to a generic pointer, and assume that
2556		 any machine which distinguishes int * from fd_set *
2557		 (I would be amazed if there are any such machines)
2558		 have an appropriate prototype somewhere or other.  */
2559	      (void) select (0, (pointer) NULL, (pointer) NULL,
2560			     (pointer) NULL, &s);
2561
2562	      /* Here either the select finished sleeping or we got a
2563		 SIGALRM.  If the latter occurred, fSalarm was set to
2564		 TRUE; it will be checked at the top of the loop.  */
2565	    }
2566	}
2567#endif /* HAVE_BSD_TTY */
2568    }
2569
2570  /* Turn off the pending SIGALRM and return.  */
2571
2572  usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
2573  alarm (0);
2574  usysdep_end_catch ();
2575
2576  return fret;
2577}
2578
2579/* Read from a port with separate read/write file descriptors.  */
2580
2581boolean
2582fsdouble_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
2583     struct sconnection *qconn;
2584     char *zbuf;
2585     size_t *pclen;
2586     size_t cmin;
2587     int ctimeout;
2588     boolean freport;
2589{
2590  struct ssysdep_conn *qsysdep;
2591
2592  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
2593  qsysdep->o = qsysdep->ord;
2594  return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport);
2595}
2596
2597/* Write data to a connection.  This routine handles all types of
2598   connections, including TLI.  */
2599
2600boolean
2601fsysdep_conn_write (qconn, zwrite, cwrite)
2602     struct sconnection *qconn;
2603     const char *zwrite;
2604     size_t cwrite;
2605{
2606  struct ssysdep_conn *q;
2607  int czero;
2608
2609  q = (struct ssysdep_conn *) qconn->psysdep;
2610
2611  /* We want blocking writes here.  */
2612  if (! fsblock (q, TRUE))
2613    return FALSE;
2614
2615  czero = 0;
2616
2617  while (cwrite > 0)
2618    {
2619      int cdid;
2620
2621      /* Loop until we don't get an interrupt.  */
2622      while (TRUE)
2623	{
2624	  /* If we've received a signal, don't continue.  */
2625	  if (FGOT_QUIT_SIGNAL ())
2626	    return FALSE;
2627
2628#if HAVE_TLI
2629	  if (q->ftli)
2630	    {
2631	      cdid = t_snd (q->o, (char *) zwrite, cwrite, 0);
2632	      if (cdid < 0 && t_errno != TSYSERR)
2633		{
2634		  ulog (LOG_ERROR, "t_snd: %s",
2635			(t_errno >= 0 && t_errno < t_nerr
2636			 ? t_errlist[t_errno]
2637			 : "unknown TLI error"));
2638		  return FALSE;
2639		}
2640	    }
2641	  else
2642#endif
2643	    cdid = write (q->o, zwrite, cwrite);
2644
2645	  if (cdid >= 0)
2646	    break;
2647	  if (errno != EINTR)
2648	    break;
2649
2650	  /* We were interrupted by a signal.  Log it.  */
2651	  ulog (LOG_ERROR, (const char *) NULL);
2652	}
2653
2654      if (cdid < 0)
2655	{
2656	  if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
2657	    {
2658	      ulog (LOG_ERROR, "write: %s", strerror (errno));
2659	      return FALSE;
2660	    }
2661	  cdid = 0;
2662	}
2663
2664      if (cdid == 0)
2665	{
2666	  /* On some systems write will return 0 if carrier is lost.
2667	     If we fail to write anything ten times in a row, we
2668	     assume that this has happened.  This is hacked in like
2669	     this because there seems to be no reliable way to tell
2670	     exactly why the write returned 0.  */
2671	  ++czero;
2672	  if (czero >= 10)
2673	    {
2674	      ulog (LOG_ERROR, "Line disconnected");
2675	      return FALSE;
2676	    }
2677	}
2678      else
2679	{
2680	  czero = 0;
2681
2682	  cwrite -= cdid;
2683	  zwrite += cdid;
2684	}
2685    }
2686
2687  return TRUE;
2688}
2689
2690/* Write to a port with separate read/write file descriptors.  */
2691
2692boolean
2693fsdouble_write (qconn, zwrite, cwrite)
2694     struct sconnection *qconn;
2695     const char *zwrite;
2696     size_t cwrite;
2697{
2698  struct ssysdep_conn *qsysdep;
2699
2700  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
2701  qsysdep->o = qsysdep->ord;
2702  if (! fsblock (qsysdep, TRUE))
2703    return FALSE;
2704  qsysdep->o = qsysdep->owr;
2705  return fsysdep_conn_write (qconn, zwrite, cwrite);
2706}
2707
2708/* The fsysdep_conn_io routine is supposed to both read and write data
2709   until it has either filled its read buffer or written out all the
2710   data it was given.  This lets us write out large packets without
2711   losing incoming data.  It handles all types of connections,
2712   including TLI.  */
2713
2714boolean
2715fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
2716     struct sconnection *qconn;
2717     const char *zwrite;
2718     size_t *pcwrite;
2719     char *zread;
2720     size_t *pcread;
2721{
2722  struct ssysdep_conn *q;
2723  size_t cwrite, cread;
2724  int czero;
2725
2726  q = (struct ssysdep_conn *) qconn->psysdep;
2727
2728  cwrite = *pcwrite;
2729  *pcwrite = 0;
2730  cread = *pcread;
2731  *pcread = 0;
2732
2733  czero = 0;
2734
2735  while (TRUE)
2736    {
2737      int cgot, cdid;
2738      size_t cdo;
2739
2740      /* This used to always use nonblocking writes, but it turns out
2741	 that some systems don't support them on terminals.
2742
2743	 The current algorithm is:
2744	     loop:
2745	       unblocked read
2746	       if read buffer full, return
2747	       if nothing to write, return
2748	       if HAVE_UNBLOCKED_WRITES
2749	         write all data
2750	       else
2751	         write up to SINGLE_WRITE bytes
2752	       if all data written, return
2753	       if no data written
2754	         if select works
2755		   select on the write descriptor with a ten second timeout
2756		 else
2757		   blocked write of one byte with a ten second alarm
2758
2759	 This algorithm should work whether the system supports
2760	 unblocked writes on terminals or not.  If the system supports
2761	 unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will
2762	 call write more often than it needs to.  If the system does
2763	 not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1,
2764	 then the write may hang so long that incoming data is lost.
2765	 This is actually possible at high baud rates on any system
2766	 when a blocking write is done; there is no solution, except
2767	 hardware handshaking.
2768
2769	 If we were not able to write any data, then we need to block
2770	 until we can write something.  The code used to simply do a
2771	 blocking write.  However, that fails when a bidirectional
2772	 protocol is permitted to push out enough bytes to fill the
2773	 entire pipe between the two communicating uucico processes.
2774	 They can both block on writing, because neither is reading.
2775
2776	 In this case, we use select.  We could select on both the
2777	 read and write descriptor, but on some systems that would
2778	 lead to calling read on each byte, which would be very
2779	 inefficient.  Instead, we select only on the write
2780	 descriptor.  After the select succeeds or times out, we retry
2781	 the read.
2782
2783	 Of course, some systems don't have select, and on some
2784	 systems that have it it doesn't work on terminal devices.  If
2785	 we can't use select, then we do a blocked write of a single
2786	 byte after setting an alarm.  We only write a single byte to
2787	 avoid any confusion as to whether or not the byte was
2788	 actually written.  */
2789
2790      /* If we are running on standard input, we switch the file
2791	 descriptors by hand.  */
2792      if (q->ord >= 0)
2793	q->o = q->ord;
2794
2795      /* Do an unblocked read.  */
2796      if (! fsblock (q, FALSE))
2797	return FALSE;
2798
2799      /* Loop until we get something (error or data) other than an
2800	 acceptable EINTR.  */
2801      while (TRUE)
2802	{
2803	  /* If we've received a signal, don't continue.  */
2804	  if (FGOT_QUIT_SIGNAL ())
2805	    return FALSE;
2806
2807#if HAVE_TLI
2808	  if (q->ftli)
2809	    {
2810	      int iflags;
2811
2812	      cgot = t_rcv (q->o, zread, cread, &iflags);
2813	      if (cgot < 0)
2814		{
2815		  if (t_errno == TNODATA)
2816		    errno = EAGAIN;
2817		  else if (t_errno != TSYSERR)
2818		    {
2819		      ulog (LOG_ERROR, "t_rcv: %s",
2820			    (t_errno >= 0 && t_errno < t_nerr
2821			     ? t_errlist[t_errno]
2822			     : "unknown TLI error"));
2823		      return FALSE;
2824		    }
2825		}
2826	    }
2827	  else
2828#endif
2829	    cgot = read (q->o, zread, cread);
2830
2831	  if (cgot >= 0)
2832	    break;
2833	  if (errno != EINTR)
2834	    break;
2835
2836	  /* We got interrupted by a signal.  Log it.  */
2837	  ulog (LOG_ERROR, (const char *) NULL);
2838	}
2839
2840      if (cgot < 0)
2841	{
2842	  if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
2843	    {
2844	      ulog (LOG_ERROR, "read: %s", strerror (errno));
2845	      return FALSE;
2846	    }
2847	  cgot = 0;
2848	}
2849
2850      cread -= cgot;
2851      zread += cgot;
2852      *pcread += cgot;
2853
2854      /* If we've filled the read buffer, or we have nothing left to
2855	 write, return out.  */
2856      if (cread == 0 || cwrite == 0)
2857	return TRUE;
2858
2859      /* The port is currently unblocked.  Do a write.  */
2860      cdo = cwrite;
2861
2862#if ! HAVE_UNBLOCKED_WRITES
2863      if (q->fterminal && cdo > SINGLE_WRITE)
2864	cdo = SINGLE_WRITE;
2865#endif
2866
2867      if (q->owr >= 0)
2868	q->o = q->owr;
2869
2870      /* Loop until we get something besides EINTR.  */
2871      while (TRUE)
2872	{
2873	  /* If we've received a signal, don't continue.  */
2874	  if (FGOT_QUIT_SIGNAL ())
2875	    return FALSE;
2876
2877#if HAVE_TLI
2878	  if (q->ftli)
2879	    {
2880	      cdid = t_snd (q->o, (char *) zwrite, cdo, 0);
2881	      if (cdid < 0)
2882		{
2883		  if (t_errno == TFLOW)
2884		    errno = EAGAIN;
2885		  else if (t_errno != TSYSERR)
2886		    {
2887		      ulog (LOG_ERROR, "t_snd: %s",
2888			    (t_errno >= 0 && t_errno < t_nerr
2889			     ? t_errlist[t_errno]
2890			     : "unknown TLI error"));
2891		      return FALSE;
2892		    }
2893		}
2894	    }
2895	  else
2896#endif
2897	    cdid = write (q->o, zwrite, cdo);
2898
2899	  if (cdid >= 0)
2900	    break;
2901	  if (errno != EINTR)
2902	    break;
2903
2904	  /* We got interrupted by a signal.  Log it.  */
2905	  ulog (LOG_ERROR, (const char *) NULL);
2906	}
2907
2908      if (cdid < 0)
2909	{
2910	  if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
2911	    {
2912	      ulog (LOG_ERROR, "write: %s", strerror (errno));
2913	      return FALSE;
2914	    }
2915	  cdid = 0;
2916	}
2917
2918      if (cdid > 0)
2919	{
2920	  /* We wrote some data.  If we wrote everything, return out.
2921	     Otherwise loop around and do another read.  */
2922	  cwrite -= cdid;
2923	  zwrite += cdid;
2924	  *pcwrite += cdid;
2925
2926	  if (cwrite == 0)
2927	    return TRUE;
2928
2929	  czero = 0;
2930	}
2931      else
2932	{
2933#if HAVE_SELECT
2934	  struct timeval stime;
2935#ifdef FD_ZERO
2936	  fd_set smask;
2937#else
2938	  int smask;
2939#endif
2940	  int c;
2941
2942	  /* We didn't write any data.  Call select.  We use a timeout
2943             long enough for 1024 bytes to be sent.  But we don't wait
2944             longer than the times it takes to receive cread bytes, in
2945             case our read buffer is small.
2946	       secs/kbyte == (1024 bytes/kbyte * 10 bits/byte) / baud bits/sec
2947	       usecs/kbyte == (((1024 bytes/kbyte * 1000000 usecs/sec)
2948	                        / baud bits/sec)
2949			       * 10 bits/byte)
2950
2951	     */
2952	  if (q->fterminal)
2953	    {
2954	      unsigned long cwait;
2955
2956	      cwait = 1024;
2957	      if (cwait > cread)
2958		cwait = cread;
2959	      stime.tv_sec = (cwait * 10) / q->ibaud;
2960	      stime.tv_usec = ((((cwait * 1000000) / q->ibaud) * 10)
2961			       % 1000000);
2962	    }
2963	  else
2964	    {
2965	      /* This is some sort of network connection.  We can't
2966                 estimate how long it will take to write data.  It
2967                 also doesn't matter as much, as most systems will
2968                 buffer much more incoming network data than they will
2969                 incoming serial data.  Sleep for a second, although
2970                 normally the select will return sonner because we can
2971                 write more data.  */
2972	      stime.tv_sec = 1;
2973	      stime.tv_usec = 0;
2974	    }
2975
2976#ifdef FD_ZERO
2977	  FD_ZERO (&smask);
2978	  FD_SET (q->o, &smask);
2979#else
2980	  smask = 1 << q->o;
2981	  if (smask == 0)
2982	    ulog (LOG_FATAL, "fsysdep_conn_io: File descriptors too large");
2983#endif
2984
2985	  /* If we've received a signal, don't continue.  */
2986	  if (FGOT_QUIT_SIGNAL ())
2987	    return FALSE;
2988
2989	  DEBUG_MESSAGE0 (DEBUG_PORT, "fsysdep_conn_io: Calling select");
2990
2991	  /* We don't bother to loop on EINTR.  If we get a signal, we
2992             just loop around and try the read and write again.  */
2993	  c = select (q->o + 1, (pointer) NULL, (pointer) &smask,
2994		      (pointer) NULL, &stime);
2995	  if (c < 0 && errno == EINTR)
2996	    {
2997	      /* We got interrupted by a signal.  Log it.  */
2998	      ulog (LOG_ERROR, (const char *) NULL);
2999	    }
3000	  else if (c >= 0)
3001	    {
3002	      /* The select either discovered that we could write
3003                 something, or it timed out.  Either way, we go around
3004                 the main read/write loop again.  */
3005	    }
3006	  else
3007#endif /* HAVE_SELECT */
3008	    {
3009	      int ierr;
3010
3011	      /* Either the select failed for some reason other than
3012	      	 EINTR, or the system does not support select at all.
3013	      	 Fall back on a timed write.  We don't worry about why
3014	      	 the select might have failed, we just assume that it
3015	      	 will not succeed on this descriptor.  */
3016
3017#if HAVE_RESTARTABLE_SYSCALLS
3018	      /* If HAVE_RESTARTABLE_SYSCALLS, then receiving an alarm
3019                 signal in the middle of a write will not cause the
3020                 write to return EINTR, and the only way to interrupt
3021                 the write is to longjmp out of it (see sysh.unx).
3022                 That is unreliable, because it means that we won't
3023                 know whether the byte was actually written or not.
3024                 However, I believe that the only system on which we
3025                 need to do this longjmp is BSD 4.2, and that system
3026                 supports select, so we should never execute this
3027                 case.  */
3028	      ulog (LOG_FATAL, "fsysdep_conn_io: Unsupported case; see code");
3029#endif
3030
3031	      if (q->ord >= 0)
3032		q->o = q->ord;
3033
3034	      if (! fsblock (q, TRUE))
3035		return FALSE;
3036
3037	      DEBUG_MESSAGE0 (DEBUG_PORT, "fsysdep_conn_io: Blocking write");
3038
3039	      if (q->owr >= 0)
3040		q->o = q->owr;
3041
3042	      /* If we've received a signal, don't continue.  */
3043	      if (FGOT_QUIT_SIGNAL ())
3044		return FALSE;
3045
3046	      /* Start up an alarm to interrupt the write.  Note that
3047                 we don't need to use the catch stuff, since we know
3048                 that HAVE_RESTARTABLE_SYSCALLS is 0.  */
3049	      usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
3050	      if (q->fterminal)
3051		alarm ((int) ((long) 10240 / q->ibaud) + 1);
3052	      else
3053		alarm (1);
3054
3055	      /* There is a race condition here: on a severely loaded
3056                 system, we could get the alarm before we start the
3057                 write call.  This would not be a disaster; often the
3058                 write will succeed anyhow.  */
3059#if HAVE_TLI
3060	      if (q->ftli)
3061		{
3062		  cdid = t_snd (q->o, (char *) zwrite, 1, 0);
3063		  if (cdid < 0 && t_errno != TSYSERR)
3064		    {
3065		      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
3066		      alarm (0);
3067		      ulog (LOG_ERROR, "t_snd: %s",
3068			    (t_errno >= 0 && t_errno < t_nerr
3069			     ? t_errlist[t_errno]
3070			     : "unknown TLI error"));
3071		      return FALSE;
3072		    }
3073		}
3074	      else
3075#endif
3076		cdid = write (q->o, zwrite, 1);
3077
3078	      ierr = errno;
3079
3080	      /* Note that we don't really care whether the write
3081                 finished because the byte was written out or whether
3082                 it finished because the alarm was triggered.  Either
3083                 way, we are going to loop around and try another
3084                 read.  */
3085
3086	      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
3087	      alarm (0);
3088
3089	      if (cdid < 0)
3090		{
3091		  if (ierr == EINTR)
3092		    {
3093		      /* We got interrupted by a signal.  Log it.  */
3094		      ulog (LOG_ERROR, (const char *) NULL);
3095		    }
3096		  else
3097		    {
3098		      ulog (LOG_ERROR, "write: %s", strerror (ierr));
3099		      return FALSE;
3100		    }
3101		}
3102	      else if (cdid == 0)
3103		{
3104		  /* On some systems write will return 0 if carrier is
3105		     lost.  If we fail to write anything ten times in
3106		     a row, we assume that this has happened.  This is
3107		     hacked in like this because there seems to be no
3108		     reliable way to tell exactly why the write
3109		     returned 0.  */
3110		  ++czero;
3111		  if (czero >= 10)
3112		    {
3113		      ulog (LOG_ERROR, "Line disconnected");
3114		      return FALSE;
3115		    }
3116		}
3117	      else
3118		{
3119		  cwrite -= cdid;
3120		  zwrite += cdid;
3121		  *pcwrite += cdid;
3122		  czero = 0;
3123		}
3124	    }
3125	}
3126    }
3127}
3128
3129/* Send a break character to a serial port.  */
3130
3131static boolean
3132fsserial_break (qconn)
3133     struct sconnection *qconn;
3134{
3135  struct ssysdep_conn *q;
3136
3137  q = (struct ssysdep_conn *) qconn->psysdep;
3138
3139#if HAVE_BSD_TTY
3140  (void) ioctl (q->o, TIOCSBRK, 0);
3141  sleep (2);
3142  (void) ioctl (q->o, TIOCCBRK, 0);
3143  return TRUE;
3144#endif /* HAVE_BSD_TTY */
3145#if HAVE_SYSV_TERMIO
3146  (void) ioctl (q->o, TCSBRK, 0);
3147  return TRUE;
3148#endif /* HAVE_SYSV_TERMIO */
3149#if HAVE_POSIX_TERMIOS
3150  return tcsendbreak (q->o, 0) == 0;
3151#endif /* HAVE_POSIX_TERMIOS */
3152}
3153
3154/* Send a break character to a stdin port.  */
3155
3156static boolean
3157fsstdin_break (qconn)
3158     struct sconnection *qconn;
3159{
3160  struct ssysdep_conn *qsysdep;
3161
3162  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
3163  qsysdep->o = qsysdep->owr;
3164  return fsserial_break (qconn);
3165}
3166
3167/* Change the setting of a serial port.  */
3168
3169/*ARGSUSED*/
3170static boolean
3171fsserial_set (qconn, tparity, tstrip, txonxoff)
3172     struct sconnection *qconn;
3173     enum tparitysetting tparity;
3174     enum tstripsetting tstrip;
3175     enum txonxoffsetting txonxoff;
3176{
3177  register struct ssysdep_conn *q;
3178  boolean fchanged, fdo;
3179  unsigned int iset = 0;
3180  unsigned int iclear = 0;
3181
3182  q = (struct ssysdep_conn *) qconn->psysdep;
3183
3184  if (! q->fterminal)
3185    return TRUE;
3186
3187  fchanged = FALSE;
3188
3189  /* Set the parity for output characters.  */
3190
3191#if HAVE_BSD_TTY
3192
3193  /* This will also cause parity detection on input characters.  */
3194
3195  fdo = FALSE;
3196  switch (tparity)
3197    {
3198    case PARITYSETTING_DEFAULT:
3199      break;
3200    case PARITYSETTING_NONE:
3201#if HAVE_PARITY_BUG
3202      /* The Sony NEWS mishandles this for some reason.  */
3203      iset = 0;
3204      iclear = ANYP;
3205#else
3206      iset = ANYP;
3207      iclear = 0;
3208#endif
3209      fdo = TRUE;
3210      break;
3211    case PARITYSETTING_EVEN:
3212      iset = EVENP;
3213      iclear = ODDP;
3214      fdo = TRUE;
3215      break;
3216    case PARITYSETTING_ODD:
3217      iset = ODDP;
3218      iclear = EVENP;
3219      fdo = TRUE;
3220      break;
3221    case PARITYSETTING_MARK:
3222    case PARITYSETTING_SPACE:
3223      /* Not supported.  */
3224      break;
3225    }
3226
3227  if (fdo)
3228    {
3229      if ((q->snew.stty.sg_flags & iset) != iset
3230	  || (q->snew.stty.sg_flags & iclear) != 0)
3231	{
3232	  q->snew.stty.sg_flags |= iset;
3233	  q->snew.stty.sg_flags &=~ iclear;
3234	  fchanged = TRUE;
3235	}
3236    }
3237
3238#else /* ! HAVE_BSD_TTY */
3239
3240  fdo = FALSE;
3241  switch (tparity)
3242    {
3243    case PARITYSETTING_DEFAULT:
3244      break;
3245    case PARITYSETTING_NONE:
3246      iset = CS8;
3247      iclear = PARENB | PARODD | (CSIZE &~ CS8);
3248      fdo = TRUE;
3249      break;
3250    case PARITYSETTING_EVEN:
3251      iset = PARENB | CS7;
3252      iclear = PARODD | (CSIZE &~ CS7);
3253      fdo = TRUE;
3254      break;
3255    case PARITYSETTING_ODD:
3256      iset = PARENB | PARODD | CS7;
3257      iclear = CSIZE &~ CS7;
3258      fdo = TRUE;
3259      break;
3260    case PARITYSETTING_MARK:
3261    case PARITYSETTING_SPACE:
3262      /* Not supported.  */
3263      break;
3264    }
3265
3266  if (fdo)
3267    {
3268      if ((q->snew.c_cflag & iset) != iset
3269	  || (q->snew.c_cflag & iclear) != 0)
3270	{
3271	  q->snew.c_cflag |= iset;
3272	  q->snew.c_cflag &=~ iclear;
3273	  fchanged = TRUE;
3274	}
3275    }
3276
3277#endif /* ! HAVE_BSD_TTY */
3278
3279  /* Set whether input characters are stripped to seven bits.  */
3280
3281#if HAVE_BSD_TTY
3282
3283#ifdef LPASS8
3284  {
3285    int i;
3286
3287    i = LPASS8;
3288    if (tstrip == STRIPSETTING_EIGHTBITS)
3289      {
3290	i = LPASS8;
3291	(void) ioctl (q->o, TIOCLBIS, &i);
3292      }
3293    else if (tstrip == STRIPSETTING_SEVENBITS)
3294      {
3295	i = LPASS8;
3296	(void) ioctl (q->o, TIOCLBIC, &i);
3297      }
3298  }
3299#endif
3300
3301#else /* ! HAVE_BSD_TTY */
3302
3303  fdo = FALSE;
3304  switch (tstrip)
3305    {
3306    case STRIPSETTING_DEFAULT:
3307      break;
3308    case STRIPSETTING_EIGHTBITS:
3309      iset = 0;
3310      iclear = ISTRIP;
3311      fdo = TRUE;
3312      break;
3313    case STRIPSETTING_SEVENBITS:
3314      iset = ISTRIP;
3315      iclear = 0;
3316      fdo = TRUE;
3317      break;
3318    }
3319
3320  if (fdo)
3321    {
3322      if ((q->snew.c_iflag & iset) != iset
3323	  || (q->snew.c_iflag & iclear) != 0)
3324	{
3325	  q->snew.c_iflag |= iset;
3326	  q->snew.c_iflag &=~ iclear;
3327	  fchanged = TRUE;
3328	}
3329    }
3330
3331#endif /* ! HAVE_BSD_TTY */
3332
3333  /* Set XON/XOFF handshaking.  */
3334
3335#if HAVE_BSD_TTY
3336
3337  fdo = FALSE;
3338  switch (txonxoff)
3339    {
3340    case XONXOFF_DEFAULT:
3341      break;
3342    case XONXOFF_OFF:
3343      iset = RAW;
3344      iclear = TANDEM | CBREAK;
3345      fdo = TRUE;
3346      break;
3347    case XONXOFF_ON:
3348      iset = CBREAK | TANDEM;
3349      iclear = RAW;
3350      fdo = TRUE;
3351      break;
3352    }
3353
3354  if (fdo)
3355    {
3356      if ((q->snew.stty.sg_flags & iset) != iset
3357	  || (q->snew.stty.sg_flags & iclear) != 0)
3358	{
3359	  q->snew.stty.sg_flags |= iset;
3360	  q->snew.stty.sg_flags &=~ iclear;
3361	  fchanged = TRUE;
3362	}
3363    }
3364
3365#else /* ! HAVE_BSD_TTY */
3366
3367  fdo = FALSE;
3368  switch (txonxoff)
3369    {
3370    case XONXOFF_DEFAULT:
3371      break;
3372    case XONXOFF_OFF:
3373      iset = 0;
3374      iclear = IXON | IXOFF;
3375      fdo = TRUE;
3376      break;
3377    case XONXOFF_ON:
3378#ifdef CRTSCTS
3379#if HAVE_POSIX_TERMIOS
3380      /* This is system dependent, but I haven't figured out a good
3381	 way around it yet.  If we are doing hardware flow control, we
3382	 don't send XON/XOFF characters but we do recognize them.  */
3383      if ((q->snew.c_cflag & CRTSCTS) != 0)
3384	{
3385	  iset = IXON;
3386	  iclear = IXOFF;
3387	  fdo = TRUE;
3388	  break;
3389	}
3390#endif /* HAVE_POSIX_TERMIOS */
3391#endif /* defined (CRTSCTS) */
3392#ifdef CRTSFL
3393      if ((q->snew.c_cflag & CRTSFL) != 0)
3394	{
3395	  iset = IXON;
3396	  iclear = IXOFF;
3397	  /* SCO says we cant have CRTSFL **and** RTSFLOW/CTSFLOW */
3398#ifdef RTSFLOW
3399	  iclear |= RTSFLOW;
3400#endif
3401#ifdef CTSFLOW
3402	  iclear |= CTSFLOW;
3403#endif
3404	  fdo = TRUE;
3405	  break;
3406	}
3407#endif /* defined(CRTSFL) */
3408      iset = IXON | IXOFF;
3409      iclear = 0;
3410      fdo = TRUE;
3411      break;
3412    }
3413
3414  if (fdo)
3415    {
3416      if ((q->snew.c_iflag & iset) != iset
3417	  || (q->snew.c_iflag & iclear) != 0)
3418	{
3419	  q->snew.c_iflag |= iset;
3420	  q->snew.c_iflag &=~ iclear;
3421	  fchanged = TRUE;
3422	}
3423    }
3424
3425#endif /* ! HAVE_BSD_TTY */
3426
3427  if (fchanged)
3428    {
3429      if (! fsetterminfodrain (q->o, &q->snew))
3430	{
3431	  ulog (LOG_ERROR, "Can't change terminal settings: %s",
3432		strerror (errno));
3433	  return FALSE;
3434	}
3435    }
3436
3437#if HAVE_BSD_TTY
3438  if (txonxoff == XONXOFF_ON
3439      && (q->snew.stty.sg_flags & ANYP) == ANYP)
3440    {
3441      int i;
3442
3443      /* At least on Ultrix, we seem to have to set LLITOUT and
3444	 LPASS8.  This shouldn't foul things up anywhere else.  As far
3445	 as I can tell, this has to be done after setting the terminal
3446	 into cbreak mode, not before.  */
3447#ifndef LLITOUT
3448#define LLITOUT 0
3449#endif
3450#ifndef LPASS8
3451#define LPASS8 0
3452#endif
3453#ifndef LAUTOFLOW
3454#define LAUTOFLOW 0
3455#endif
3456      i = LLITOUT | LPASS8 | LAUTOFLOW;
3457      (void) ioctl (q->o, TIOCLBIS, &i);
3458
3459#if HAVE_STRIP_BUG
3460      /* Ultrix 4.0 has a peculiar problem: setting CBREAK always
3461	 causes input characters to be stripped.  I hope this does not
3462	 apply to other BSD systems.  It is possible to work around
3463	 this by using the termio call.  I wish this sort of stuff was
3464	 not necessary!!!  */
3465      {
3466	struct termio s;
3467
3468	if (ioctl (q->o, TCGETA, &s) >= 0)
3469	  {
3470	    s.c_iflag &=~ ISTRIP;
3471	    (void) ioctl (q->o, TCSETA, &s);
3472	  }
3473      }
3474#endif /* HAVE_STRIP_BUG */
3475    }
3476#endif /* HAVE_BSD_TTY */
3477
3478  return TRUE;
3479}
3480
3481/* Change settings of a stdin port.  */
3482
3483static boolean
3484fsstdin_set (qconn, tparity, tstrip, txonxoff)
3485     struct sconnection *qconn;
3486     enum tparitysetting tparity;
3487     enum tstripsetting tstrip;
3488     enum txonxoffsetting txonxoff;
3489{
3490  struct ssysdep_conn *qsysdep;
3491
3492  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
3493  qsysdep->o = qsysdep->ord;
3494  return fsserial_set (qconn, tparity, tstrip, txonxoff);
3495}
3496
3497/* Run a chat program.  */
3498
3499static boolean
3500fsrun_chat (oread, owrite, pzprog)
3501     int oread;
3502     int owrite;
3503     char **pzprog;
3504{
3505  int aidescs[3];
3506  FILE *e;
3507  pid_t ipid;
3508  char *z;
3509  size_t c;
3510
3511  aidescs[0] = oread;
3512  aidescs[1] = owrite;
3513  aidescs[2] = SPAWN_READ_PIPE;
3514
3515  /* Pass fkeepuid, fkeepenv and fshell as TRUE.  This puts the
3516     responsibility of maintaing security on the chat program.  */
3517  ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE,
3518		   (const char *) NULL, FALSE, TRUE, (const char *) NULL,
3519		   (const char *) NULL, (const char *) NULL);
3520  if (ipid < 0)
3521    {
3522      ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno));
3523      return FALSE;
3524    }
3525
3526  e = fdopen (aidescs[2], (char *) "r");
3527  if (e == NULL)
3528    {
3529      ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
3530      (void) close (aidescs[2]);
3531      (void) kill (ipid, SIGKILL);
3532      (void) ixswait ((unsigned long) ipid, (const char *) NULL);
3533      return FALSE;
3534    }
3535
3536  /* The FILE e now is attached to stderr of the program.  Forward
3537     every line the program outputs to the log file.  */
3538  z = NULL;
3539  c = 0;
3540  while (getline (&z, &c, e) > 0)
3541    {
3542      size_t clen;
3543
3544      clen = strlen (z);
3545      if (z[clen - 1] == '\n')
3546	z[clen - 1] = '\0';
3547      if (*z != '\0')
3548	ulog (LOG_NORMAL, "chat: %s", z);
3549    }
3550
3551  xfree ((pointer) z);
3552  (void) fclose (e);
3553
3554  return ixswait ((unsigned long) ipid, "Chat program") == 0;
3555}
3556
3557/* Run a chat program on a port using separate read/write file
3558   descriptors.  */
3559
3560boolean
3561fsdouble_chat (qconn, pzprog)
3562     struct sconnection *qconn;
3563     char **pzprog;
3564{
3565  struct ssysdep_conn *qsysdep;
3566  boolean fret;
3567
3568  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
3569  fret = fsrun_chat (qsysdep->ord, qsysdep->owr, pzprog);
3570  if (qsysdep->fterminal)
3571    (void) fgetterminfo (qsysdep->ord, &qsysdep->snew);
3572  return fret;
3573}
3574
3575/* Run a chat program on any general type of connection.  */
3576
3577boolean
3578fsysdep_conn_chat (qconn, pzprog)
3579     struct sconnection *qconn;
3580     char **pzprog;
3581{
3582  struct ssysdep_conn *qsysdep;
3583  boolean fret;
3584
3585  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
3586  fret = fsrun_chat (qsysdep->o, qsysdep->o, pzprog);
3587  if (qsysdep->fterminal)
3588    (void) fgetterminfo (qsysdep->o, &qsysdep->snew);
3589  return fret;
3590}
3591
3592/* Return baud rate of a serial port.  */
3593
3594static long
3595isserial_baud (qconn)
3596     struct sconnection *qconn;
3597{
3598  struct ssysdep_conn *qsysdep;
3599
3600  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
3601  return qsysdep->ibaud;
3602}
3603