home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / uucp-1.04 / unix / serial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-13  |  69.1 KB  |  2,978 lines

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