Annotation of coherent/g/usr/lib/uucp/tay104/unix/serial.c, revision 1.1

1.1     ! root        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 [email protected] 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.1 93/07/30 08:02:47 bin Exp Locker: bin $";
        !            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+5))
        !           618:            {
        !           619:              ulog (LOG_NORMAL, "%s: port already locked", z+5);
        !           620:              fret = FALSE;
        !           621:            }
        !           622:          else
        !           623:            fret = (fscoherent_disable_tty (z + 5, &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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.