|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.