2747 lines
66 KiB
Plaintext
2747 lines
66 KiB
Plaintext
/* sys2.unx
|
||
The system dependent communication routines for UNIX.
|
||
|
||
Copyright (C) 1991, 1992 Ian Lance Taylor
|
||
|
||
This file is part of the Taylor UUCP package.
|
||
|
||
This program is free software; you can redistribute it and/or
|
||
modify it under the terms of the GNU General Public License as
|
||
published by the Free Software Foundation; either version 2 of the
|
||
License, or (at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful, but
|
||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
||
The author of the program may be contacted at ian@airs.com or
|
||
c/o AIRS, P.O. Box 520, Waltham, MA 02254.
|
||
|
||
$Log: sys2.unx,v $
|
||
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
|
||
initial import of 386bsd-0.1 sources
|
||
|
||
Revision 1.72 1992/04/03 17:43:39 ian
|
||
Petri Helenius: don't clobber undefined bits in termio or termios
|
||
|
||
Revision 1.71 1992/04/01 21:52:04 ian
|
||
T. William Wells: handle a system without <poll.h> or <stropts.h>
|
||
|
||
Revision 1.70 1992/03/30 15:29:58 ian
|
||
Added HAVE_SVR4_LOCKFILES
|
||
|
||
Revision 1.69 1992/03/29 22:25:27 ian
|
||
Always block and unblock read and write descriptors together
|
||
|
||
Revision 1.68 1992/03/28 04:12:17 ian
|
||
Gerben Wierda: minor cleanups
|
||
|
||
Revision 1.67 1992/03/28 03:06:04 ian
|
||
Don't use TIOCEXCL locking
|
||
|
||
Revision 1.66 1992/03/28 02:47:30 ian
|
||
Rework HAVE_UNBLOCKED_WRITES to work even if writes are unblocked
|
||
|
||
Revision 1.65 1992/03/17 15:35:28 ian
|
||
Log signals when they happen, even if we continue looping
|
||
|
||
Revision 1.64 1992/03/17 05:01:33 ian
|
||
Don't block when opening the write descriptor
|
||
|
||
Revision 1.63 1992/03/17 01:03:03 ian
|
||
Miscellaneous cleanup
|
||
|
||
Revision 1.62 1992/03/16 01:23:08 ian
|
||
Make blocking writes optional
|
||
|
||
Revision 1.61 1992/03/15 07:15:42 ian
|
||
T. William Wells: don't use unblocked writes
|
||
|
||
Revision 1.60 1992/03/15 04:51:17 ian
|
||
Keep an array of signals we've received rather than a single variable
|
||
|
||
Revision 1.59 1992/03/15 01:54:46 ian
|
||
All execs are now done in isspawn, all waits are done in iswait
|
||
|
||
Revision 1.58 1992/03/12 21:50:50 ian
|
||
Moved local header includes above sleep routine determination
|
||
|
||
Revision 1.57 1992/03/12 19:54:43 ian
|
||
Debugging based on types rather than number
|
||
|
||
Revision 1.56 1992/03/11 02:09:57 ian
|
||
Franc,ois Pinard: retry fork several times before giving up
|
||
|
||
Revision 1.55 1992/03/09 22:11:46 ian
|
||
Franc,ois Pinard: sleep for a second after closing a serial port
|
||
|
||
Revision 1.54 1992/03/09 22:07:36 ian
|
||
Wait for terminal output to drain at various points
|
||
|
||
Revision 1.53 1992/03/08 16:56:51 ian
|
||
Ted Lindgreen: if CRTSCTS is defined, don't turn on IXOFF
|
||
|
||
Revision 1.52 1992/03/08 04:56:21 ian
|
||
Peter da Silva: added ``lockname'' command for ports
|
||
|
||
Revision 1.51 1992/03/08 01:56:01 ian
|
||
Include <sys/ioctl.h> if we have it
|
||
|
||
Revision 1.50 1992/03/08 01:37:45 ian
|
||
Suppurt TIOCEXCL locking
|
||
|
||
Revision 1.49 1992/03/07 16:25:21 ian
|
||
Preserve unknown bits in c_cflag
|
||
|
||
Revision 1.48 1992/03/04 23:43:39 ian
|
||
Petri Helenius: didn't remove lock file if open failed
|
||
|
||
Revision 1.47 1992/03/04 01:40:51 ian
|
||
Thomas Fischer: tweaked a bit for the NeXT
|
||
|
||
Revision 1.46 1992/03/03 21:01:20 ian
|
||
Use strict timeout in fsserial_read, eliminate all race conditions
|
||
|
||
Revision 1.45 1992/03/03 04:25:00 ian
|
||
T. William Wells: don't arbitrarily extend read timeout
|
||
|
||
Revision 1.44 1992/03/02 04:53:07 ian
|
||
Marc Unangst: added HAVE_SCO_LOCKFILES configuration parameter
|
||
|
||
Revision 1.43 1992/02/28 05:06:15 ian
|
||
T. William Wells: fsysdep_catch must be a macro
|
||
|
||
Revision 1.42 1992/02/27 05:40:54 ian
|
||
T. William Wells: detach from controlling terminal, handle signals safely
|
||
|
||
Revision 1.41 1992/02/24 21:22:47 ian
|
||
The poll function takes milliseconds, not microseconds (my error)
|
||
|
||
Revision 1.40 1992/02/24 21:18:17 ian
|
||
Roberto Biancardi: use poll for sleeping if we haven't got anything else
|
||
|
||
Revision 1.39 1992/02/24 20:07:43 ian
|
||
John Theus: some systems don't have <fcntl.h>
|
||
|
||
Revision 1.38 1992/02/23 03:26:51 ian
|
||
Overhaul to use automatic configure shell script
|
||
|
||
Revision 1.37 1992/02/17 22:08:50 ian
|
||
Bob Denny: log chat script messages as LOG_NORMAL, not LOG_ERROR
|
||
|
||
Revision 1.36 1992/02/08 20:02:36 ian
|
||
Added HAVE_SETRET configuration option for systems without setjmp
|
||
|
||
Revision 1.35 1992/02/08 03:54:18 ian
|
||
Include <string.h> only in <uucp.h>, added 1992 copyright
|
||
|
||
Revision 1.34 1992/01/16 16:32:44 ian
|
||
Mike Park: ioctl is sometimes declared varadic, so we can't declare it
|
||
|
||
Revision 1.33 1992/01/15 21:06:11 ian
|
||
Mike Park: some systems can't include <sys/time.h> and <time.h> together
|
||
|
||
Revision 1.32 1992/01/15 20:40:04 ian
|
||
Mike Park: some systems don't have <limits.h>
|
||
|
||
Revision 1.31 1992/01/15 19:40:35 ian
|
||
Mike Park: handle HAVE_UNION_WAIT correctly and completely
|
||
|
||
Revision 1.30 1992/01/14 04:18:47 ian
|
||
Chip Salzenberg: added HAVE_USLEEP configuration parameter
|
||
|
||
Revision 1.29 1992/01/13 06:11:39 ian
|
||
David Nugent: can't declare open or fcntl
|
||
|
||
Revision 1.28 1991/12/31 04:16:19 ian
|
||
Chip Salzenberg: don't turn on IXON and IXOFF at the start
|
||
|
||
Revision 1.27 1991/12/29 04:04:18 ian
|
||
Added a bunch of extern definitions
|
||
|
||
Revision 1.26 1991/12/29 00:55:23 ian
|
||
Monty Solomon: added HAVE_UNION_WAIT
|
||
|
||
Revision 1.25 1991/12/22 22:14:19 ian
|
||
Monty Solomon: added HAVE_UNISTD_H configuration parameter
|
||
|
||
Revision 1.24 1991/12/20 02:23:10 ian
|
||
Don't change port settings if we don't have to
|
||
|
||
Revision 1.23 1991/12/19 04:25:57 ian
|
||
Terry Gardner: configuration parameter to not use both NONBLOCK and NDELAY
|
||
|
||
Revision 1.22 1991/12/17 23:14:08 ian
|
||
T. William Wells: allow dialer complete and abort to be chat scripts
|
||
|
||
Revision 1.21 1991/12/17 22:31:15 ian
|
||
Start in RAW mode, to avoid dropping characters when we switch to it
|
||
|
||
Revision 1.20 1991/12/17 05:24:01 ian
|
||
David Nugent: flush pending input in fsserial_open
|
||
|
||
Revision 1.19 1991/12/15 04:28:23 ian
|
||
Don't turn on ISTRIP initially
|
||
|
||
Revision 1.18 1991/12/10 19:45:05 ian
|
||
Added ulog_device to record device name for log file
|
||
|
||
Revision 1.17 1991/12/01 02:23:12 ian
|
||
Niels Baggesen: don't multiply include <unistd.h>
|
||
|
||
Revision 1.16 1991/11/26 01:50:30 ian
|
||
Set fread_blocking and fwrite_blocking correctly for TCP routines
|
||
|
||
Revision 1.15 1991/11/26 01:45:42 ian
|
||
Marty Shannon: configuration option to not include <sys/wait.h>
|
||
|
||
Revision 1.14 1991/11/22 06:05:57 ian
|
||
Gregory Gulik: fix wait status macro definitions
|
||
|
||
Revision 1.13 1991/11/21 20:58:18 ian
|
||
Brian Campbell: for HAVE_SIGSETJMP use sigjmp_buf, not jmp_buf
|
||
|
||
Revision 1.12 1991/11/15 23:13:53 ian
|
||
Fixed termio(s) version of fsserial_set
|
||
|
||
Revision 1.11 1991/11/13 20:38:00 ian
|
||
Added TCP port type for connections over TCP
|
||
|
||
Revision 1.10 1991/11/12 19:07:27 ian
|
||
Be careful to only call fsetterminfo on a terminal
|
||
|
||
Revision 1.9 1991/11/11 23:47:24 ian
|
||
Added chat-program to run a program to do a chat script
|
||
|
||
Revision 1.8 1991/11/11 00:39:45 ian
|
||
Open port in seven bit mode, added fport_set to change to eight bit
|
||
|
||
Revision 1.7 1991/11/08 22:52:34 ian
|
||
Brian Campbell: only include <sys/time.h> and <sys/ioctl.h> when needed
|
||
|
||
Revision 1.6 1991/11/08 22:11:45 ian
|
||
Brian Campbell: allow sigsetjmp as configuration option
|
||
|
||
Revision 1.5 1991/11/07 22:52:11 ian
|
||
Chip Salzenberg: force stdin and stdout to stay open in case of spawning
|
||
|
||
Revision 1.4 1991/11/07 21:43:59 ian
|
||
Chip Salzenberg: set terminal modes directly, don't or them in
|
||
|
||
Revision 1.3 1991/11/07 19:42:16 ian
|
||
Chip Salzenberg: declare inline functions consistently
|
||
|
||
Revision 1.2 1991/11/07 19:32:28 ian
|
||
Chip Salzenberg: allow LOCKDIR, and check that locking process exists
|
||
|
||
Revision 1.1 1991/09/10 19:45:50 ian
|
||
Initial revision
|
||
|
||
*/
|
||
|
||
#include "uucp.h"
|
||
|
||
#if USE_RCS_ID
|
||
char sys2_unx_rcsid[] = "$Id: sys2.unx,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
|
||
#endif
|
||
|
||
#include <errno.h>
|
||
|
||
#if HAVE_LIMITS_H
|
||
#include <limits.h>
|
||
#endif
|
||
|
||
#if USE_STDIO && HAVE_UNISTD_H
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
#include "system.h"
|
||
#include "sysdep.h"
|
||
#include "port.h"
|
||
|
||
/* Pick a timing routine to use. I somewhat arbitrarily picked usleep
|
||
above nap above napms above poll above select. */
|
||
|
||
#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
|
||
#define USE_SELECT_TIMER 0
|
||
#else
|
||
#define USE_SELECT_TIMER HAVE_SELECT
|
||
#endif
|
||
|
||
#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
|
||
#undef HAVE_POLL
|
||
#define HAVE_POLL 0
|
||
#endif
|
||
|
||
#if HAVE_USLEEP || HAVE_NAP
|
||
#undef HAVE_NAPMS
|
||
#define HAVE_NAPMS 0
|
||
#endif
|
||
|
||
#if HAVE_USLEEP
|
||
#undef HAVE_NAP
|
||
#define HAVE_NAP 0
|
||
#endif
|
||
|
||
#if HAVE_FCNTL_H
|
||
#include <fcntl.h>
|
||
#else
|
||
#if HAVE_SYS_FILE_H
|
||
#include <sys/file.h>
|
||
#endif
|
||
#endif
|
||
|
||
#ifndef O_RDONLY
|
||
#define O_RDONLY 0
|
||
#define O_WRONLY 1
|
||
#define O_RDWR 2
|
||
#endif
|
||
|
||
#if HAVE_SYS_IOCTL_H
|
||
#include <sys/ioctl.h>
|
||
#endif
|
||
|
||
#if USE_SELECT_TIMER || HAVE_BSD_TTY
|
||
#include <sys/time.h>
|
||
#endif
|
||
|
||
#if HAVE_POLL
|
||
#if HAVE_STROPTS_H
|
||
#include <stropts.h>
|
||
#endif
|
||
#if HAVE_POLL_H
|
||
#include <poll.h>
|
||
#endif
|
||
#if ! HAVE_STROPTS_H && ! HAVE_POLL_H
|
||
/* We need a definition for struct pollfd, although it doesn't matter
|
||
what it contains. It's used in usysdep_pause. */
|
||
struct pollfd
|
||
{
|
||
int idummy;
|
||
};
|
||
#endif /* ! HAVE_STROPTS_H && ! HAVE_POLL_H */
|
||
#endif /* HAVE_POLL */
|
||
|
||
#if HAVE_TIME_H
|
||
#if HAVE_SYS_TIME_AND_TIME_H || (! USE_SELECT_TIMER && ! HAVE_BSD_TTY)
|
||
#include <time.h>
|
||
#endif
|
||
#endif
|
||
|
||
/* Get definitions for both O_NONBLOCK and O_NDELAY. */
|
||
|
||
#ifndef O_NDELAY
|
||
#ifdef FNDELAY
|
||
#define O_NDELAY FNDELAY
|
||
#else /* ! defined (FNDELAY) */
|
||
#define O_NDELAY 0
|
||
#endif /* ! defined (FNDELAY) */
|
||
#endif /* ! defined (O_NDELAY) */
|
||
|
||
#ifndef O_NONBLOCK
|
||
#ifdef FNBLOCK
|
||
#define O_NONBLOCK FNBLOCK
|
||
#else /* ! defined (FNBLOCK) */
|
||
#define O_NONBLOCK 0
|
||
#endif /* ! defined (FNBLOCK) */
|
||
#endif /* ! defined (O_NONBLOCK) */
|
||
|
||
#if O_NDELAY == 0 && O_NONBLOCK == 0
|
||
#error No way to do nonblocking I/O
|
||
#endif
|
||
|
||
/* If we can define them both together, do so. This is because some
|
||
ancient drivers on some systems appear to look for one but not the
|
||
other. Otherwise just use O_NONBLOCK. */
|
||
#if COMBINED_UNBLOCK
|
||
#define FILE_UNBLOCKED (O_NDELAY | O_NONBLOCK)
|
||
#else
|
||
#define FILE_UNBLOCKED O_NONBLOCK
|
||
#endif
|
||
|
||
/* Get definitions for both EAGAIN and EWOULDBLOCK. */
|
||
|
||
#ifndef EAGAIN
|
||
#ifndef EWOULDBLOCK
|
||
#define EAGAIN (-1)
|
||
#define EWOULDBLOCK (-1)
|
||
#else /* defined (EWOULDBLOCK) */
|
||
#define EAGAIN EWOULDBLOCK
|
||
#endif /* defined (EWOULDBLOCK) */
|
||
#else /* defined (EAGAIN) */
|
||
#ifndef EWOULDBLOCK
|
||
#define EWOULDBLOCK EAGAIN
|
||
#endif /* ! defined (EWOULDBLOCK) */
|
||
#endif /* defined (EAGAIN) */
|
||
|
||
/* Make sure we have a definition for MAX_INPUT. */
|
||
|
||
#ifndef MAX_INPUT
|
||
#define MAX_INPUT (256)
|
||
#endif
|
||
|
||
/* Make sure we have definitions for major and minor. */
|
||
|
||
#ifndef major
|
||
#define major(i) (((i) >> 8) & 0xff)
|
||
#endif
|
||
#ifndef minor
|
||
#define minor(i) ((i) & 0xff)
|
||
#endif
|
||
|
||
/* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal.
|
||
Otherwise, if we have the TIOCEXCL ioctl call, we have to open the
|
||
terminal before we know that it is unlocked. */
|
||
#ifdef TIOCSINUSE
|
||
#define HAVE_TIOCSINUSE 1
|
||
#else
|
||
#ifdef TIOCEXCL
|
||
#define HAVE_TIOCEXCL 1
|
||
#endif
|
||
#endif
|
||
|
||
/* Determine bits to clear for the various terminal control fields for
|
||
HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS. */
|
||
|
||
#if HAVE_SYSV_TERMIO
|
||
#define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
|
||
| ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
|
||
| IXON | IXANY | IXOFF)
|
||
#define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
|
||
| OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
|
||
| VTDLY | FFDLY)
|
||
#define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD)
|
||
#define ISET_CFLAG (CS8 | CREAD | HUPCL)
|
||
#define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
|
||
| ECHONL | NOFLSH)
|
||
#endif
|
||
#if HAVE_POSIX_TERMIOS
|
||
#define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
|
||
| INLCR | INPCK | ISTRIP | IXOFF | IXON \
|
||
| PARMRK)
|
||
#define ICLEAR_OFLAG (OPOST)
|
||
#define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD)
|
||
#define ISET_CFLAG (CS8 | CREAD | HUPCL)
|
||
#define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
|
||
| ISIG | NOFLSH | TOSTOP)
|
||
#endif
|
||
|
||
/* External functions. */
|
||
extern char *strlwr ();
|
||
extern int close (), pipe (), dup2 (), read (), write ();
|
||
extern int fclose ();
|
||
extern void _exit ();
|
||
#if USE_SELECT_TIMER || HAVE_BSD_TTY
|
||
extern int select ();
|
||
#endif
|
||
#if HAVE_NAP
|
||
extern int nap ();
|
||
#endif
|
||
#if HAVE_NAPMS
|
||
extern int napms ();
|
||
#endif
|
||
#if HAVE_POLL
|
||
extern int poll ();
|
||
#endif
|
||
|
||
/* Local functions. */
|
||
|
||
static SIGtype usalarm P((int isig));
|
||
static boolean fsserial_lockfile P((boolean flok, const struct sport *,
|
||
const char *zdevice));
|
||
static boolean fsserial_lock P((const struct sport *qport,
|
||
struct ssysdep_serial_port *q,
|
||
boolean fin, const char *zdevice));
|
||
static boolean fsserial_open P((const char *z, long ibaud, boolean fwait,
|
||
struct ssysdep_serial_port *q));
|
||
__inline__ static boolean fsblock P((struct ssysdep_serial_port *q,
|
||
boolean fblock));
|
||
static boolean fsserial_close P((struct ssysdep_serial_port *q));
|
||
static boolean fsserial_reset P((struct ssysdep_serial_port *q));
|
||
static boolean fsserial_read P((struct ssysdep_serial_port *q,
|
||
char *zbuf, int *pclen, int cmin,
|
||
int ctimeout, boolean freport,
|
||
boolean fpty));
|
||
static boolean fsserial_write P((struct ssysdep_serial_port *q,
|
||
const char *zwrite, int cwrite));
|
||
static boolean fsserial_io P((struct ssysdep_serial_port *q,
|
||
const char *zwrite, int *pcwrite,
|
||
char *zread, int *pcread));
|
||
static boolean fsserial_break P((struct ssysdep_serial_port *q));
|
||
static boolean fsserial_set P((struct ssysdep_serial_port *q,
|
||
enum tportsetting tset));
|
||
static boolean fsrun_chat P((int oread, int owrite, const char *zprog));
|
||
|
||
/* This code handles SIGALRM. See the discussion above fsserial_read.
|
||
Normally we ignore SIGALRM, but the handler will temporarily be set
|
||
to this function, which should set fSalarm and then either longjmp
|
||
or schedule another SIGALRM. fSalarm is never referred to outside
|
||
of this file, but we don't make it static to try to fool compilers
|
||
which don't understand volatile. */
|
||
|
||
volatile sig_atomic_t fSalarm;
|
||
|
||
static SIGtype
|
||
usalarm (isig)
|
||
int isig;
|
||
{
|
||
#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
|
||
(void) signal (isig, usalarm);
|
||
#endif
|
||
|
||
fSalarm = TRUE;
|
||
|
||
#if HAVE_RESTARTABLE_SYSCALLS
|
||
longjmp (sSjmp_buf, 1);
|
||
#else
|
||
alarm (1);
|
||
#endif
|
||
}
|
||
|
||
/* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and
|
||
SIGPIPE and another to restore the original state. When these
|
||
functions are called (in fsysdep_modem_close) SIGHUP is being
|
||
ignored. The routines are isblocksigs, which returns a value of
|
||
type HELD_SIG_MASK and usunblocksigs which takes a single argument
|
||
of type HELD_SIG_MASK. */
|
||
|
||
#if HAVE_SIGPROCMASK
|
||
|
||
/* Use the POSIX sigprocmask call. */
|
||
|
||
extern int sigprocmask ();
|
||
|
||
#define HELD_SIG_MASK sigset_t
|
||
|
||
static sigset_t isblocksigs P((void));
|
||
|
||
static sigset_t
|
||
isblocksigs ()
|
||
{
|
||
sigset_t sblock, sold;
|
||
|
||
sigemptyset (&sblock);
|
||
sigaddset (&sblock, SIGINT);
|
||
sigaddset (&sblock, SIGQUIT);
|
||
sigaddset (&sblock, SIGTERM);
|
||
sigaddset (&sblock, SIGPIPE);
|
||
sigprocmask (SIG_BLOCK, &sblock, &sold);
|
||
return sold;
|
||
}
|
||
|
||
#define usunblocksigs(s) \
|
||
((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL))
|
||
|
||
#else /* ! HAVE_SIGPROCMASK */
|
||
#if HAVE_SIGBLOCK
|
||
|
||
/* Use the BSD sigblock and sigsetmask calls. */
|
||
|
||
extern int sigblock (), sigsetmask ();
|
||
|
||
#define HELD_SIG_MASK int
|
||
|
||
#ifndef sigmask
|
||
#define sigmask(i) (1 << ((i) - 1))
|
||
#endif
|
||
|
||
#define isblocksigs() \
|
||
sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \
|
||
| sigmask (SIGTERM) | sigmask (SIGPIPE))
|
||
|
||
#define usunblocksigs(i) ((void) sigsetmask (i))
|
||
|
||
#else /* ! HAVE_SIGBLOCK */
|
||
|
||
#if HAVE_SIGHOLD
|
||
|
||
/* Use the SVR3 sighold and sigrelse calls. */
|
||
|
||
extern int sighold (), sigrelse ();
|
||
|
||
#define HELD_SIG_MASK int
|
||
|
||
static int isblocksigs P((void));
|
||
|
||
static int
|
||
isblocksigs ()
|
||
{
|
||
sighold (SIGINT);
|
||
sighold (SIGQUIT);
|
||
sighold (SIGTERM);
|
||
sighold (SIGPIPE);
|
||
return 0;
|
||
}
|
||
|
||
static void usunblocksigs P((int));
|
||
|
||
/*ARGSUSED*/
|
||
static void
|
||
usunblocksigs (i)
|
||
int i;
|
||
{
|
||
sigrelse (SIGINT);
|
||
sigrelse (SIGQUIT);
|
||
sigrelse (SIGTERM);
|
||
sigrelse (SIGPIPE);
|
||
}
|
||
|
||
#else /* ! HAVE_SIGHOLD */
|
||
|
||
/* We have no way to block signals. This system will suffer from a
|
||
race condition in fsysdep_modem_close. */
|
||
|
||
#define HELD_SIG_MASK int
|
||
|
||
#define isblocksigs() 0
|
||
|
||
#define usunblocksigs(i)
|
||
|
||
#endif /* ! HAVE_SIGHOLD */
|
||
#endif /* ! HAVE_SIGBLOCK */
|
||
#endif /* ! HAVE_SIGPROCMASK */
|
||
|
||
/* Pause for half a second. This doesn't really belong in this file,
|
||
but all the timing routines are here. */
|
||
|
||
void
|
||
usysdep_pause ()
|
||
{
|
||
#if HAVE_NAPMS
|
||
napms (500);
|
||
#endif /* HAVE_NAPMS */
|
||
#if HAVE_NAP
|
||
nap (500L);
|
||
#endif /* HAVE_NAP */
|
||
#if HAVE_USLEEP
|
||
usleep (500 * (long) 1000);
|
||
#endif /* HAVE_USLEEP */
|
||
#if HAVE_POLL
|
||
struct pollfd sdummy;
|
||
|
||
/* We need to pass an unused pollfd structure because poll checks
|
||
the address before checking the number of elements. */
|
||
poll (&sdummy, 0, 500);
|
||
#endif /* HAVE_POLL */
|
||
#if USE_SELECT_TIMER
|
||
struct timeval s;
|
||
|
||
s.tv_sec = 0;
|
||
s.tv_usec = 500 * (long) 1000;
|
||
select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s);
|
||
#endif /* USE_SELECT_TIMER */
|
||
#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP
|
||
#if ! USE_SELECT_TIMER && ! HAVE_POLL
|
||
sleep (1);
|
||
#endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */
|
||
#endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */
|
||
}
|
||
|
||
/* This routine is used for both locking and unlocking. It is the
|
||
only routine which knows how to translate a device name into the
|
||
name of a lock file. If it can't figure out a name, it does
|
||
nothing and returns TRUE. */
|
||
|
||
static boolean
|
||
fsserial_lockfile (flok, qport, zdevice)
|
||
boolean flok;
|
||
const struct sport *qport;
|
||
const char *zdevice;
|
||
{
|
||
const char *z;
|
||
|
||
z = qport->zlockname;
|
||
if (z == NULL)
|
||
{
|
||
char *zalc;
|
||
|
||
z = zdevice;
|
||
if (z == NULL)
|
||
{
|
||
z = qport->zname;
|
||
if (z == NULL)
|
||
return TRUE;
|
||
}
|
||
|
||
#if ! HAVE_SVR4_LOCKFILES
|
||
if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0)
|
||
z += sizeof "/dev/" - 1;
|
||
zalc = (char *) alloca (strlen (z) + sizeof "LCK..");
|
||
sprintf (zalc, "LCK..%s", z);
|
||
#if HAVE_SCO_LOCKFILES
|
||
strlwr (zalc + sizeof "LCK.." - 1);
|
||
#endif
|
||
#else /* HAVE_SVR4_LOCKFILES */
|
||
{
|
||
struct stat s;
|
||
|
||
if (*z != '/')
|
||
{
|
||
zalc = (char *) alloca (sizeof "/dev/" + strlen (z));
|
||
sprintf (zalc, "/dev/%s", z);
|
||
z = zalc;
|
||
}
|
||
if (stat (z, &s) != 0)
|
||
{
|
||
ulog (LOG_ERROR, "stat (%s): %s", z, strerror (errno));
|
||
return FALSE;
|
||
}
|
||
zalc = (char *) alloca (sizeof "LK.123.123.123");
|
||
sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev),
|
||
major (s.st_rdev), minor (s.st_rdev));
|
||
}
|
||
#endif /* HAVE_SVR4_LOCKFILES */
|
||
|
||
z = zalc;
|
||
}
|
||
|
||
if (flok)
|
||
return fsdo_lock (z, FALSE);
|
||
else
|
||
return fsdo_unlock (z, FALSE);
|
||
}
|
||
|
||
/* If we can mark a modem line in use, then when we lock a port we
|
||
must open it and mark it in use. We can't wait until the actual
|
||
open because we can't fail out if it is locked then. */
|
||
|
||
static boolean
|
||
fsserial_lock (qport, q, fin, zdevice)
|
||
const struct sport *qport;
|
||
struct ssysdep_serial_port *q;
|
||
boolean fin;
|
||
const char *zdevice;
|
||
{
|
||
if (! fsserial_lockfile (TRUE, qport, zdevice))
|
||
return FALSE;
|
||
|
||
#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL
|
||
/* Open the line and, if possible, mark it in use. */
|
||
{
|
||
const char *z;
|
||
int oread, iflag;
|
||
|
||
z = zdevice;
|
||
if (z == NULL)
|
||
{
|
||
z = qport->zname;
|
||
if (z == NULL)
|
||
return TRUE;
|
||
}
|
||
|
||
if (fin)
|
||
iflag = 0;
|
||
else
|
||
iflag = FILE_UNBLOCKED;
|
||
|
||
if (*z != '/')
|
||
{
|
||
char *zcopy;
|
||
|
||
zcopy = (char *) alloca (sizeof "/dev/" + strlen (z));
|
||
sprintf (zcopy, "/dev/%s", z);
|
||
z = zcopy;
|
||
}
|
||
|
||
oread = open (z, O_RDWR | iflag);
|
||
if (oread < 0)
|
||
{
|
||
if (errno != EBUSY)
|
||
ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
|
||
(void) fsserial_lockfile (FALSE, qport, zdevice);
|
||
return FALSE;
|
||
}
|
||
|
||
#if HAVE_TIOCSINUSE
|
||
/* If we can't mark it in use, return FALSE to indicate that the
|
||
lock failed. */
|
||
if (ioctl (oread, TIOCSINUSE, 0) < 0)
|
||
{
|
||
if (errno != EALREADY)
|
||
ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno));
|
||
(void) close (oread);
|
||
(void) fsserial_lockfile (FALSE, qport, zdevice);
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
|
||
#ifdef TIOCSCTTY
|
||
/* On BSD 4.4, make it our controlling terminal. */
|
||
(void) ioctl (oread, TIOCSCTTY, 0);
|
||
#endif
|
||
|
||
q->oread = q->owrite = oread;
|
||
}
|
||
#endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* We don't need to lock a stdin port. */
|
||
|
||
/*ARGSUSED*/
|
||
boolean
|
||
fsysdep_stdin_lock (qport, fin)
|
||
struct sport *qport;
|
||
boolean fin;
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
/* Lock a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_lock (qport, fin)
|
||
struct sport *qport;
|
||
boolean fin;
|
||
{
|
||
return fsserial_lock (qport, &qport->u.smodem.s.s, fin,
|
||
qport->u.smodem.zdevice);
|
||
}
|
||
|
||
/* Lock a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_lock (qport, fin)
|
||
struct sport *qport;
|
||
boolean fin;
|
||
{
|
||
return fsserial_lock (qport, &qport->u.sdirect.s.s, fin,
|
||
qport->u.sdirect.zdevice);
|
||
}
|
||
|
||
/* Open a serial line. This sets the terminal settings. We begin in
|
||
seven bit mode and let the protocol change if necessary. */
|
||
|
||
static struct sbaud_table
|
||
{
|
||
#if HAVE_POSIX_TERMIOS
|
||
speed_t icode;
|
||
#else
|
||
int icode;
|
||
#endif
|
||
long ibaud;
|
||
} asSbaud_table[] =
|
||
{
|
||
{ B50, 50 },
|
||
{ B75, 75 },
|
||
{ B110, 110 },
|
||
{ B134, 134 },
|
||
{ B150, 150 },
|
||
{ B200, 200 },
|
||
{ B300, 300 },
|
||
{ B600, 600 },
|
||
{ B1200, 1200 },
|
||
{ B1800, 1800 },
|
||
{ B2400, 2400 },
|
||
{ B4800, 4800 },
|
||
{ B9600, 9600 },
|
||
#ifdef B19200
|
||
{ B19200, 19200 },
|
||
#else /* ! defined (B19200) */
|
||
#ifdef EXTA
|
||
{ EXTA, 19200 },
|
||
#endif /* EXTA */
|
||
#endif /* ! defined (B19200) */
|
||
#ifdef B38400
|
||
{ B38400, 38400 }
|
||
#else /* ! defined (B38400) */
|
||
#ifdef EXTB
|
||
{ EXTB, 38400 }
|
||
#endif /* EXTB */
|
||
#endif /* ! defined (B38400) */
|
||
};
|
||
|
||
#define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0])
|
||
|
||
#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
|
||
/* Hold the MIN value for the terminal to avoid setting it
|
||
unnecessarily. */
|
||
static int cSmin;
|
||
#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
|
||
|
||
static boolean
|
||
fsserial_open (z, ibaud, fwait, q)
|
||
const char *z;
|
||
long ibaud;
|
||
boolean fwait;
|
||
struct ssysdep_serial_port *q;
|
||
{
|
||
#if HAVE_POSIX_TERMIOS
|
||
speed_t ib;
|
||
#else
|
||
int ib;
|
||
#endif
|
||
|
||
if (z == NULL)
|
||
{
|
||
const char *zport;
|
||
boolean fdummy;
|
||
|
||
zport = zsysdep_port_name (&fdummy);
|
||
if (zport != NULL)
|
||
ulog_device (zport);
|
||
}
|
||
else
|
||
{
|
||
if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0)
|
||
ulog_device (z + sizeof "/dev/" - 1);
|
||
else
|
||
ulog_device (z);
|
||
}
|
||
|
||
ib = B0;
|
||
|
||
if (ibaud != 0)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < CBAUD_TABLE; i++)
|
||
if (asSbaud_table[i].ibaud == ibaud)
|
||
break;
|
||
if (i >= CBAUD_TABLE)
|
||
{
|
||
ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud);
|
||
if (q->oread != -1)
|
||
{
|
||
(void) close (q->oread);
|
||
if (q->oread != q->owrite)
|
||
(void) close (q->owrite);
|
||
}
|
||
return FALSE;
|
||
}
|
||
ib = asSbaud_table[i].icode;
|
||
}
|
||
|
||
/* The port may have already been opened by the locking routine. */
|
||
if (q->oread == -1)
|
||
{
|
||
int oread, owrite;
|
||
|
||
if (z == NULL)
|
||
{
|
||
oread = 0;
|
||
owrite = 1;
|
||
}
|
||
else
|
||
{
|
||
int iflag;
|
||
|
||
if (fwait)
|
||
iflag = 0;
|
||
else
|
||
iflag = FILE_UNBLOCKED;
|
||
|
||
if (*z != '/')
|
||
{
|
||
char *zcopy;
|
||
|
||
zcopy = (char *) alloca (sizeof "/dev/" + strlen (z));
|
||
sprintf (zcopy, "/dev/%s", z);
|
||
z = zcopy;
|
||
}
|
||
|
||
oread = open (z, O_RDWR | iflag);
|
||
if (oread < 0)
|
||
{
|
||
ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
|
||
return FALSE;
|
||
}
|
||
|
||
#ifdef TIOCSCTTY
|
||
/* On BSD 4.4, make it our controlling terminal. */
|
||
(void) ioctl (oread, TIOCSCTTY, 0);
|
||
#endif
|
||
|
||
owrite = oread;
|
||
}
|
||
|
||
q->oread = oread;
|
||
q->owrite = owrite;
|
||
}
|
||
|
||
/* Make sure the ports are blocking. */
|
||
|
||
if (fcntl (q->oread, F_SETFL, 0) < 0
|
||
|| (q->oread != q->owrite
|
||
&& fcntl (q->owrite, F_SETFL, 0) < 0))
|
||
{
|
||
ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
|
||
(void) close (q->oread);
|
||
if (q->oread != q->owrite)
|
||
(void) close (q->owrite);
|
||
return FALSE;
|
||
}
|
||
|
||
q->fread_blocking = TRUE;
|
||
|
||
if (! fgetterminfo (q->oread, &q->sorig))
|
||
{
|
||
q->fterminal = FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
q->fterminal = TRUE;
|
||
|
||
q->snew = q->sorig;
|
||
|
||
#if HAVE_BSD_TTY
|
||
|
||
q->snew.sg_flags = RAW | ANYP;
|
||
if (ibaud == 0)
|
||
ib = q->snew.sg_ospeed;
|
||
else
|
||
{
|
||
q->snew.sg_ispeed = ib;
|
||
q->snew.sg_ospeed = ib;
|
||
}
|
||
|
||
#ifdef TIOCHPCL
|
||
/* When the file is closed, hang up the line. This is a safety
|
||
measure in case the program crashes. */
|
||
(void) ioctl (q->oread, TIOCHPCL, 0);
|
||
#endif
|
||
|
||
#ifdef TIOCFLUSH
|
||
{
|
||
int iparam;
|
||
|
||
/* Flush pending input. */
|
||
#ifdef FREAD
|
||
iparam = FREAD;
|
||
#else
|
||
iparam = 0;
|
||
#endif
|
||
(void) ioctl (q->oread, TIOCFLUSH, &iparam);
|
||
}
|
||
#endif /* TIOCFLUSH */
|
||
|
||
#endif /* HAVE_BSD_TTY */
|
||
|
||
#if HAVE_SYSV_TERMIO
|
||
|
||
if (ibaud == 0)
|
||
ib = q->snew.c_cflag & CBAUD;
|
||
|
||
q->snew.c_iflag &=~ ICLEAR_IFLAG;
|
||
q->snew.c_oflag &=~ ICLEAR_OFLAG;
|
||
q->snew.c_cflag &=~ ICLEAR_CFLAG;
|
||
q->snew.c_cflag |= (ib | ISET_CFLAG);
|
||
q->snew.c_lflag &=~ ICLEAR_LFLAG;
|
||
cSmin = 6;
|
||
q->snew.c_cc[VMIN] = cSmin;
|
||
q->snew.c_cc[VTIME] = 0;
|
||
|
||
#ifdef TCFLSH
|
||
/* Flush pending input. */
|
||
(void) ioctl (q->oread, TCFLSH, 0);
|
||
#endif
|
||
|
||
#endif /* HAVE_SYSV_TERMIO */
|
||
|
||
#if HAVE_POSIX_TERMIOS
|
||
|
||
if (ibaud == 0)
|
||
ib = cfgetospeed (&q->snew);
|
||
|
||
q->snew.c_iflag &=~ ICLEAR_IFLAG;
|
||
q->snew.c_oflag &=~ ICLEAR_OFLAG;
|
||
q->snew.c_cflag &=~ ICLEAR_CFLAG;
|
||
q->snew.c_cflag |= ISET_CFLAG;
|
||
q->snew.c_lflag &=~ ICLEAR_LFLAG;
|
||
cSmin = 6;
|
||
q->snew.c_cc[VMIN] = cSmin;
|
||
q->snew.c_cc[VTIME] = 0;
|
||
|
||
(void) cfsetospeed (&q->snew, ib);
|
||
(void) cfsetispeed (&q->snew, ib);
|
||
|
||
/* Flush pending input. */
|
||
(void) tcflush (q->oread, TCIFLUSH);
|
||
|
||
#endif /* HAVE_POSIX_TERMIOS */
|
||
|
||
if (! fsetterminfo (q->oread, &q->snew))
|
||
{
|
||
ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
|
||
(void) close (q->oread);
|
||
if (q->oread != q->owrite)
|
||
(void) close (q->owrite);
|
||
return FALSE;
|
||
}
|
||
|
||
if (ibaud != 0)
|
||
q->ibaud = ibaud;
|
||
else
|
||
{
|
||
int i;
|
||
|
||
q->ibaud = 1200;
|
||
for (i = 0; i < CBAUD_TABLE; i++)
|
||
{
|
||
if (asSbaud_table[i].icode == ib)
|
||
{
|
||
q->ibaud = asSbaud_table[i].ibaud;
|
||
break;
|
||
}
|
||
}
|
||
|
||
DEBUG_MESSAGE1 (DEBUG_PORT,
|
||
"fsserial_open: Baud rate is %ld", q->ibaud);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Open a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_open (qport, ibaud, fwait)
|
||
struct sport *qport;
|
||
long ibaud;
|
||
boolean fwait;
|
||
{
|
||
return fsserial_open ((const char *) NULL, ibaud, fwait,
|
||
&qport->u.sstdin.s.s);
|
||
}
|
||
|
||
/* Open a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_open (qport, ibaud, fwait)
|
||
struct sport *qport;
|
||
long ibaud;
|
||
boolean fwait;
|
||
{
|
||
const char *z;
|
||
boolean fret;
|
||
|
||
z = qport->u.smodem.zdevice;
|
||
if (z == NULL)
|
||
{
|
||
z = qport->zname;
|
||
if (z == NULL)
|
||
{
|
||
ulog (LOG_ERROR, "Port has no name or device");
|
||
return FALSE;
|
||
}
|
||
}
|
||
if (ibaud == 0)
|
||
ibaud = qport->u.smodem.ibaud;
|
||
fret = fsserial_open (z, ibaud, fwait, &qport->u.smodem.s.s);
|
||
if (! fret)
|
||
(void) fsserial_lockfile (FALSE, qport, qport->u.smodem.zdevice);
|
||
return fret;
|
||
}
|
||
|
||
/* Open a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_open (qport, ibaud, fwait)
|
||
struct sport *qport;
|
||
long ibaud;
|
||
boolean fwait;
|
||
{
|
||
const char *z;
|
||
boolean fret;
|
||
|
||
z = qport->u.sdirect.zdevice;
|
||
if (z == NULL)
|
||
{
|
||
z = qport->zname;
|
||
if (z == NULL)
|
||
{
|
||
ulog (LOG_ERROR, "Port has no name or device");
|
||
return FALSE;
|
||
}
|
||
}
|
||
if (ibaud == 0)
|
||
ibaud = qport->u.sdirect.ibaud;
|
||
fret = fsserial_open (z, ibaud, fwait, &qport->u.sdirect.s.s);
|
||
if (! fret)
|
||
(void) fsserial_lockfile (FALSE, qport, qport->u.sdirect.zdevice);
|
||
return fret;
|
||
}
|
||
|
||
/* Change the blocking status of the port. We keep track of the
|
||
current blocking status to avoid calling fcntl unnecessarily; fcntl
|
||
turns out to be surprisingly expensive, at least on Ultrix. We
|
||
used to keep track of the blocking status of the read port and the
|
||
write port independently. Unfortunately, this is nonportable,
|
||
because on BSD, and probably some other systems, unblocking a
|
||
terminal applies to all descriptors to that terminal. Now, if
|
||
oread != owrite, we set both. */
|
||
|
||
__inline__
|
||
static boolean
|
||
fsblock (qs, fblock)
|
||
struct ssysdep_serial_port *qs;
|
||
boolean fblock;
|
||
{
|
||
if (fblock ? ! qs->fread_blocking : qs->fread_blocking)
|
||
{
|
||
int iset;
|
||
|
||
if (fblock)
|
||
iset = 0;
|
||
else
|
||
iset = FILE_UNBLOCKED;
|
||
if (fcntl (qs->oread, F_SETFL, iset) < 0
|
||
|| (qs->oread != qs->owrite
|
||
&& fcntl (qs->owrite, F_SETFL, iset) < 0))
|
||
{
|
||
ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
qs->fread_blocking = fblock;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/* Close a serial port. */
|
||
|
||
static boolean
|
||
fsserial_close (q)
|
||
struct ssysdep_serial_port *q;
|
||
{
|
||
if (q->oread >= 0)
|
||
{
|
||
/* Use a 30 second timeout to avoid hanging while draining
|
||
output. */
|
||
if (q->fterminal)
|
||
{
|
||
fSalarm = FALSE;
|
||
|
||
if (fsysdep_catch ())
|
||
{
|
||
usysdep_start_catch ();
|
||
usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
|
||
(void) alarm (30);
|
||
|
||
(void) fsetterminfodrain (q->oread, &q->sorig);
|
||
}
|
||
|
||
usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
|
||
(void) alarm (0);
|
||
usysdep_end_catch ();
|
||
|
||
/* If we timed out, use the non draining call. Hopefully
|
||
this can't hang. */
|
||
if (fSalarm)
|
||
(void) fsetterminfo (q->oread, &q->sorig);
|
||
}
|
||
|
||
(void) close (q->oread);
|
||
if (q->oread != q->owrite)
|
||
(void) close (q->owrite);
|
||
q->oread = q->owrite = -1;
|
||
|
||
/* Sleep for a second to give the terminal a chance to settle,
|
||
in case we are about to call out again. */
|
||
sleep (1);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Close a stdin port. */
|
||
|
||
/*ARGSUSED*/
|
||
boolean
|
||
fsysdep_stdin_close (qport, fsuccess)
|
||
struct sport *qport;
|
||
boolean fsuccess;
|
||
{
|
||
return fsserial_close (&qport->u.sstdin.s.s);
|
||
}
|
||
|
||
/* Close a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_close (qport, fsuccess)
|
||
struct sport *qport;
|
||
boolean fsuccess;
|
||
{
|
||
boolean fret;
|
||
struct sdialer *qdial;
|
||
struct sdialer sdial;
|
||
|
||
fret = TRUE;
|
||
qdial = NULL;
|
||
|
||
/* We're no longer interested in carrier. */
|
||
(void) fsysdep_modem_no_carrier (qport);
|
||
|
||
if (qport->u.smodem.zdialer != NULL)
|
||
{
|
||
char *zcopy;
|
||
|
||
zcopy = (char *) alloca (strlen (qport->u.smodem.zdialer) + 1);
|
||
strcpy (zcopy, qport->u.smodem.zdialer);
|
||
zcopy[strcspn (zcopy, " \t")] = '\0';
|
||
if (! fread_dialer_info (zcopy, &sdial))
|
||
fret = FALSE;
|
||
else
|
||
qdial = &sdial;
|
||
}
|
||
else
|
||
qdial = qport->u.smodem.qdialer;
|
||
|
||
if (qdial != NULL)
|
||
{
|
||
boolean fsighup_ignored;
|
||
HELD_SIG_MASK smask;
|
||
int i;
|
||
sig_atomic_t afhold[INDEXSIG_COUNT];
|
||
const struct schat_info *qchat;
|
||
|
||
/* The port I/O routines check whether any signal has been
|
||
received, and abort if one has. While we are closing down
|
||
the modem, we don't care if we received a signal in the past,
|
||
but we do care if we receive a new signal (otherwise it would
|
||
be difficult to kill a uucico which was closing down a
|
||
modem). We never care if we get SIGHUP at this point. So we
|
||
turn off SIGHUP, remember what signals we've already seen,
|
||
and clear our notion of what signals we've seen. We have to
|
||
block the signals while we remember and clear the array,
|
||
since we might otherwise miss a signal which occurred between
|
||
the copy and the clear (old systems can't block signals; they
|
||
will just have to suffer the race). */
|
||
|
||
usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored);
|
||
smask = isblocksigs ();
|
||
for (i = 0; i < INDEXSIG_COUNT; i++)
|
||
{
|
||
afhold[i] = afSignal[i];
|
||
afSignal[i] = FALSE;
|
||
}
|
||
usunblocksigs (smask);
|
||
|
||
if (fsuccess)
|
||
qchat = &qdial->scomplete;
|
||
else
|
||
qchat = &qdial->sabort;
|
||
if (! fchat (qchat, (const struct ssysteminfo *) NULL,
|
||
(const struct sdialer *) NULL, (const char *) NULL,
|
||
FALSE, qport->zname, qport->u.smodem.s.s.ibaud))
|
||
fret = FALSE;
|
||
|
||
/* Restore the old signal array and the SIGHUP handler. It is
|
||
not necessary to block signals here, since all we are doing
|
||
is exactly what the signal handler itself would do if the
|
||
signal occurred. */
|
||
for (i = 0; i < INDEXSIG_COUNT; i++)
|
||
if (afhold[i])
|
||
afSignal[i] = TRUE;
|
||
if (! fsighup_ignored)
|
||
usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
|
||
}
|
||
|
||
if (! fsserial_close (&qport->u.smodem.s.s))
|
||
fret = FALSE;
|
||
|
||
if (! fsserial_lockfile (FALSE, qport, qport->u.smodem.zdevice))
|
||
fret = FALSE;
|
||
|
||
return fret;
|
||
}
|
||
|
||
/* Close a direct port. */
|
||
|
||
/*ARGSUSED*/
|
||
boolean
|
||
fsysdep_direct_close (qport, fsuccess)
|
||
struct sport *qport;
|
||
boolean fsuccess;
|
||
{
|
||
boolean fret;
|
||
|
||
fret = fsserial_close (&qport->u.sdirect.s.s);
|
||
|
||
if (! fsserial_lockfile (FALSE, qport, qport->u.sdirect.zdevice))
|
||
fret = FALSE;
|
||
|
||
return fret;
|
||
}
|
||
|
||
/* Reset a serial port by hanging up. */
|
||
|
||
#if ! HAVE_POSIX_TERMIOS
|
||
|
||
static boolean
|
||
fsserial_reset (q)
|
||
struct ssysdep_serial_port *q;
|
||
{
|
||
sterminal sbaud;
|
||
|
||
if (! q->fterminal)
|
||
return TRUE;
|
||
|
||
sbaud = q->snew;
|
||
|
||
#if HAVE_BSD_TTY
|
||
sbaud.sg_ispeed = B0;
|
||
sbaud.sg_ospeed = B0;
|
||
#else /* ! HAVE_BSD_TTY */
|
||
sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
|
||
#endif /* ! HAVE_BSD_TTY */
|
||
|
||
if (! fsetterminfodrain (q->oread, &sbaud))
|
||
ulog (LOG_FATAL, "Can't hangup terminal: %s", strerror (errno));
|
||
|
||
/* Give the terminal a chance to settle. */
|
||
sleep (1);
|
||
|
||
if (! fsetterminfo (q->oread, &q->snew))
|
||
ulog (LOG_FATAL, "Can't reopen terminal: %s", strerror (errno));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#else /* HAVE_POSIX_TERMIOS */
|
||
|
||
static boolean
|
||
fsserial_reset (q)
|
||
struct ssysdep_serial_port *q;
|
||
{
|
||
sterminal sbaud;
|
||
speed_t iin, iout;
|
||
|
||
if (! q->fterminal)
|
||
return TRUE;
|
||
|
||
iin = cfgetispeed (&q->snew);
|
||
iout = cfgetospeed (&q->snew);
|
||
|
||
sbaud = q->snew;
|
||
|
||
if (cfsetospeed (&sbaud, B0) != 0
|
||
|| ! fsetterminfodrain (q->oread, &sbaud))
|
||
ulog (LOG_FATAL, "Can't hangup terminal: %s", strerror (errno));
|
||
|
||
/* Give the terminal a chance to settle. */
|
||
sleep (1);
|
||
|
||
if (cfsetispeed (&q->snew, iin) != 0
|
||
|| cfsetospeed (&q->snew, iout) != 0
|
||
|| ! fsetterminfo (q->oread, &q->snew))
|
||
ulog (LOG_FATAL, "Can't reopen terminal: %s", strerror (errno));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#endif /* HAVE_POSIX_TERMIOS */
|
||
|
||
/* Reset a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_reset (qport)
|
||
struct sport *qport;
|
||
{
|
||
return fsserial_reset (&qport->u.sstdin.s.s);
|
||
}
|
||
|
||
/* Reset a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_reset (qport)
|
||
struct sport *qport;
|
||
{
|
||
return fsserial_reset (&qport->u.smodem.s.s);
|
||
}
|
||
|
||
/* Reset a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_reset (qport)
|
||
struct sport *qport;
|
||
{
|
||
return fsserial_reset (&qport->u.sdirect.s.s);
|
||
}
|
||
|
||
/* Begin dialing out on a modem port. This opens the dialer device if
|
||
there is one. */
|
||
|
||
boolean
|
||
fsysdep_modem_begin_dial (qport, qdial)
|
||
struct sport *qport;
|
||
struct sdialer *qdial;
|
||
{
|
||
#ifdef TIOCMODEM
|
||
/* If we can tell the modem to obey modem control, do so. */
|
||
{
|
||
int iperm;
|
||
|
||
iperm = 0;
|
||
(void) ioctl (qport->u.smodem.s.s.oread, TIOCMODEM, &iperm);
|
||
}
|
||
#endif /* TIOCMODEM */
|
||
|
||
#ifdef TIOCCDTR
|
||
/* If we supposed to toggle DTR, do so. */
|
||
|
||
if (qdial->fdtr_toggle)
|
||
{
|
||
(void) ioctl (qport->u.smodem.s.s.oread, TIOCCDTR, 0);
|
||
(void) ioctl (qport->u.smodem.s.s.oread, TIOCSDTR, 0);
|
||
|
||
if (qdial->fdtr_toggle_wait)
|
||
sleep (1);
|
||
}
|
||
#endif /* TIOCCDTR */
|
||
|
||
if (! fsysdep_modem_no_carrier (qport))
|
||
return FALSE;
|
||
|
||
/* Open the dial device if there is one. */
|
||
if (qport->u.smodem.zdial_device != NULL)
|
||
{
|
||
const char *z;
|
||
int oread;
|
||
|
||
qport->u.smodem.s.s.oholdread = qport->u.smodem.s.s.oread;
|
||
qport->u.smodem.s.s.oholdwrite = qport->u.smodem.s.s.owrite;
|
||
|
||
z = qport->u.smodem.zdial_device;
|
||
if (*z != '/')
|
||
{
|
||
char *zcopy;
|
||
|
||
zcopy = (char *) alloca (sizeof "/dev/" + strlen (z));
|
||
sprintf (zcopy, "/dev/%s", z);
|
||
z = zcopy;
|
||
}
|
||
|
||
oread = open (z, O_RDWR);
|
||
if (oread < 0)
|
||
{
|
||
ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
|
||
return FALSE;
|
||
}
|
||
|
||
qport->u.smodem.s.s.oread = qport->u.smodem.s.s.owrite = oread;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Tell the port to not require carrier. I don't know how to do this
|
||
on a BSD system that doesn't support TIOCNCAR, if there are any
|
||
such systems. */
|
||
|
||
boolean
|
||
fsysdep_modem_no_carrier (qport)
|
||
struct sport *qport;
|
||
{
|
||
if (! qport->u.smodem.s.s.fterminal)
|
||
return TRUE;
|
||
|
||
#ifdef TIOCNCAR
|
||
/* Tell the modem to ignore carrier. */
|
||
if (ioctl (qport->u.smodem.s.s.oread, TIOCNCAR, 0) < 0)
|
||
{
|
||
ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
#endif /* TIOCNCAR */
|
||
|
||
#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
|
||
/* Put the modem into local mode (ignore carrier) to start the chat
|
||
script. */
|
||
qport->u.smodem.s.s.snew.c_cflag |= CLOCAL;
|
||
if (! fsetterminfo (qport->u.smodem.s.s.oread,
|
||
&qport->u.smodem.s.s.snew))
|
||
{
|
||
ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Tell the port to require carrier. If the port does not support
|
||
carrier, we do nothing. We do not need to worry whether the
|
||
dialer supports carrier, since this will only be called when
|
||
explicitly requested by a dialer chat script. */
|
||
|
||
boolean
|
||
fsysdep_modem_need_carrier (qport)
|
||
struct sport *qport;
|
||
{
|
||
if (! qport->u.smodem.s.s.fterminal)
|
||
return TRUE;
|
||
|
||
if (qport->u.smodem.fcarrier)
|
||
{
|
||
#ifdef TIOCCAR
|
||
/* Tell the modem to pay attention to carrier. */
|
||
if (ioctl (qport->u.smodem.s.s.oread, TIOCCAR, 0) < 0)
|
||
{
|
||
ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
#endif /* TIOCCAR */
|
||
|
||
#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
|
||
/* Put the modem into nonlocal mode. */
|
||
qport->u.smodem.s.s.snew.c_cflag &=~ CLOCAL;
|
||
if (! fsetterminfo (qport->u.smodem.s.s.oread,
|
||
&qport->u.smodem.s.s.snew))
|
||
{
|
||
ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Finish dialing out on a modem by closing any dialer device and waiting
|
||
for carrier. */
|
||
|
||
boolean
|
||
fsysdep_modem_end_dial (qport, qdial)
|
||
struct sport *qport;
|
||
struct sdialer *qdial;
|
||
{
|
||
if (qport->u.smodem.zdial_device != NULL)
|
||
{
|
||
(void) close (qport->u.smodem.s.s.oread);
|
||
qport->u.smodem.s.s.oread = qport->u.smodem.s.s.oholdread;
|
||
qport->u.smodem.s.s.owrite = qport->u.smodem.s.s.oholdwrite;
|
||
}
|
||
|
||
if (qport->u.smodem.fcarrier && qdial->fcarrier)
|
||
{
|
||
/* Tell the port that we need carrier. */
|
||
|
||
if (! fsysdep_modem_need_carrier (qport))
|
||
return FALSE;
|
||
|
||
#ifdef TIOCWONLINE
|
||
|
||
/* We know how to wait for carrier, so do so. */
|
||
|
||
/* If we already got a signal, just quit now. */
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
|
||
/* This bit of code handles signals just like fsserial_read
|
||
does. See that function for a longer explanation. */
|
||
|
||
/* Use fsysdep_catch to handle a longjmp from the signal
|
||
handler. */
|
||
|
||
fSalarm = FALSE;
|
||
|
||
if (fsysdep_catch ())
|
||
{
|
||
/* Start catching SIGALRM; normally we ignore it. */
|
||
usysdep_start_catch ();
|
||
usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
|
||
(void) alarm (qdial->ccarrier_wait);
|
||
|
||
/* We really don't care if we get an error, since that will
|
||
probably just mean that TIOCWONLINE isn't supported in
|
||
which case there's nothing we can do anyhow. If we get
|
||
SIGINT we want to keep waiting for carrier, because
|
||
SIGINT just means don't start any new sessions. We don't
|
||
handle SIGINT correctly if we do a longjmp in the signal
|
||
handler; too bad. */
|
||
while (ioctl (qport->u.smodem.s.s.oread, TIOCWONLINE, 0) < 0
|
||
&& errno == EINTR)
|
||
{
|
||
/* Log the signal. */
|
||
ulog (LOG_ERROR, (const char *) NULL);
|
||
if (FGOT_QUIT_SIGNAL () || fSalarm)
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Turn off the pending SIGALRM and ignore SIGALARM again. */
|
||
usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
|
||
(void) alarm (0);
|
||
usysdep_end_catch ();
|
||
|
||
/* If we got a random signal, just return FALSE. */
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
|
||
/* If we timed out, give an error. */
|
||
if (fSalarm)
|
||
{
|
||
ulog (LOG_ERROR, "Timed out waiting for carrier");
|
||
return FALSE;
|
||
}
|
||
|
||
#endif /* TIOCWONLINE */
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Read data from a serial port, with a timeout.
|
||
|
||
This function should return when we have read cmin characters or
|
||
the timeout has occurred. We have to work a bit to get UNIX to do
|
||
this efficiently. The simple implementation schedules a SIGALRM
|
||
signal and then calls read; if there is a single character
|
||
available, the call to read will return immediately, so there must
|
||
be a loop which terminates when the SIGALRM is delivered or the
|
||
correct number of characters has been read. This can be very
|
||
inefficient with a fast CPU or a low baud rate (or both!), since
|
||
each call to read may return only one or two characters.
|
||
|
||
Under POSIX or System V, we can specify a minimum number of
|
||
characters to read, so there is no serious trouble.
|
||
|
||
Under BSD, we figure out how many characters we have left to read,
|
||
how long it will take for them to arrive at the current baud rate,
|
||
and sleep that long.
|
||
|
||
Doing this with a timeout and avoiding all possible race conditions
|
||
get very hairy, though. Basically, we're going to schedule a
|
||
SIGALRM for when the timeout expires. I don't really want to do a
|
||
longjmp in the SIGALRM handler, though, because that may lose data.
|
||
Therefore, I have the signal handler set a variable. However, this
|
||
means that there will be a span of time between the time the code
|
||
checks the variable and the time it calls the read system call; if
|
||
the SIGALRM occurs during that time, the read might hang forever.
|
||
To avoid this, the SIGALRM handler not only sets a global variable,
|
||
it also schedules another SIGALRM for one second in the future
|
||
(POSIX specifies that a signal handler is permitted to safely call
|
||
alarm). To avoid getting a continual sequence of SIGALRM
|
||
interrupts, we change the signal handler to ignore SIGALRM when
|
||
we're about to exit the function. This means that every time we
|
||
execute fsserial_read we make at least five system calls. It's the
|
||
best I've been able to come up with, though.
|
||
|
||
When fsserial_read finishes, there will be no SIGALRM scheduled and
|
||
SIGALRM will be ignored. */
|
||
|
||
static boolean
|
||
fsserial_read (q, zbuf, pclen, cmin, ctimeout, freport, fpty)
|
||
struct ssysdep_serial_port *q;
|
||
char *zbuf;
|
||
int *pclen;
|
||
int cmin;
|
||
int ctimeout;
|
||
boolean freport;
|
||
boolean fpty;
|
||
{
|
||
CATCH_PROTECT int cwant;
|
||
boolean fret;
|
||
|
||
cwant = *pclen;
|
||
*pclen = 0;
|
||
|
||
/* Guard against a bad timeout. We return TRUE when a timeout
|
||
expires. It is possible to get a negative timeout here because
|
||
the calling code does not check user supplied timeouts for
|
||
plausibility. */
|
||
if (ctimeout <= 0)
|
||
return TRUE;
|
||
|
||
/* We want to do a blocking read. */
|
||
if (! fsblock (q, TRUE))
|
||
return FALSE;
|
||
|
||
fSalarm = FALSE;
|
||
|
||
/* We're going to set up an alarm signal to last for the entire
|
||
read. If the read system call cannot be interrupted, the signal
|
||
handler will do a longjmp causing fsysdep_catch (a macro) to
|
||
return FALSE. We handle that here. If read can be interrupted,
|
||
fsysdep_catch will be defined to TRUE. */
|
||
|
||
if (fsysdep_catch ())
|
||
{
|
||
/* Prepare to catch SIGALRM and schedule the signal. */
|
||
usysdep_start_catch ();
|
||
usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
|
||
alarm (ctimeout);
|
||
}
|
||
else
|
||
{
|
||
/* We caught a signal. We don't actually have to do anything,
|
||
as all the appropriate checks are made at the start of the
|
||
following loop. */
|
||
}
|
||
|
||
fret = FALSE;
|
||
|
||
while (TRUE)
|
||
{
|
||
int cgot;
|
||
|
||
#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
|
||
/* If we can tell the terminal not to return until we have a
|
||
certain number of characters, do so. */
|
||
if (q->fterminal)
|
||
{
|
||
int csetmin;
|
||
|
||
/* I'm not that confident about setting MIN to values larger
|
||
than 127, although up to 255 would probably work. */
|
||
if (cmin < 127)
|
||
csetmin = cmin;
|
||
else
|
||
csetmin = 127;
|
||
|
||
if (csetmin != cSmin)
|
||
{
|
||
q->snew.c_cc[VMIN] = csetmin;
|
||
if (! fsetterminfo (q->oread, &q->snew))
|
||
{
|
||
int ierr;
|
||
|
||
/* We turn off the signal before reporting the error
|
||
to minimize any problems with interrupted system
|
||
calls. */
|
||
ierr = errno;
|
||
usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
|
||
alarm (0);
|
||
usysdep_end_catch ();
|
||
ulog (LOG_ERROR, "Can't set MIN for terminal: %s",
|
||
strerror (ierr));
|
||
return FALSE;
|
||
}
|
||
cSmin = csetmin;
|
||
}
|
||
}
|
||
#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
|
||
|
||
/* If we've received a signal, get out now. */
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
break;
|
||
|
||
/* If we've already gotten a SIGALRM, get out with whatever
|
||
we've accumulated. */
|
||
|
||
if (fSalarm)
|
||
{
|
||
fret = TRUE;
|
||
break;
|
||
}
|
||
|
||
/* Right here is the race condition which we avoid by having the
|
||
SIGALRM handler schedule another SIGALRM. */
|
||
|
||
cgot = read (q->oread, zbuf, cwant);
|
||
|
||
/* If the read returned an error, check for signals. */
|
||
if (cgot < 0)
|
||
{
|
||
if (errno == EINTR)
|
||
{
|
||
/* Log the signal. */
|
||
ulog (LOG_ERROR, (const char *) NULL);
|
||
}
|
||
if (fSalarm)
|
||
{
|
||
fret = TRUE;
|
||
break;
|
||
}
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
break;
|
||
}
|
||
|
||
/* If read returned an error, get out. We just ignore EINTR
|
||
here, since it must be from some signal we don't care about.
|
||
If the read returned 0 then the line must have been hung up
|
||
(normally we would have received SIGHUP, but we can't count
|
||
on that). We turn off the signals before calling ulog to
|
||
reduce problems with interrupted system calls. */
|
||
if (cgot <= 0)
|
||
{
|
||
if (cgot < 0 && errno == EINTR)
|
||
cgot = 0;
|
||
else
|
||
{
|
||
int ierr;
|
||
|
||
ierr = errno;
|
||
|
||
usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
|
||
alarm (0);
|
||
usysdep_end_catch ();
|
||
|
||
if (freport)
|
||
{
|
||
if (cgot == 0)
|
||
ulog (LOG_ERROR, "Line disconnected");
|
||
else
|
||
ulog (LOG_ERROR, "read: %s", strerror (ierr));
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
cwant -= cgot;
|
||
cmin -= cgot;
|
||
zbuf += cgot;
|
||
*pclen += cgot;
|
||
|
||
/* If we have enough data, get out now. */
|
||
|
||
if (cmin <= 0)
|
||
{
|
||
fret = TRUE;
|
||
break;
|
||
}
|
||
|
||
#if HAVE_BSD_TTY
|
||
/* We still want more data, so sleep long enough for the rest of
|
||
it to arrive. We don't this for System V or POSIX because
|
||
setting MIN is good enough (we can't sleep longer than it
|
||
takes to get MAX_INPUT characters anyhow).
|
||
|
||
The baud rate is approximately 10 times the number of
|
||
characters which will arrive in one second, so the number of
|
||
milliseconds to sleep ==
|
||
characters * (milliseconds / character) ==
|
||
characters * (1000 * (seconds / character)) ==
|
||
characters * (1000 * (1 / (baud / 10))) ==
|
||
characters * (10000 / baud)
|
||
|
||
We arbitrarily reduce the sleep amount by 10 milliseconds to
|
||
attempt to account for the amount of time it takes to set up
|
||
the sleep. This is how long it takes to get half a character
|
||
at 19200 baud. We then don't bother to sleep for less than
|
||
10 milliseconds. We don't sleep if the read was interrupted.
|
||
|
||
We use select to sleep. It would be easy to use poll as
|
||
well, but it's unlikely that any system with BSD ttys would
|
||
have poll but not select. Using select avoids hassles with
|
||
the pending SIGALRM; if it hits the select will be
|
||
interrupted, and otherwise the select will not affect it. */
|
||
|
||
#if ! HAVE_SELECT
|
||
#error This code requires select; feel free to extend it
|
||
#endif
|
||
|
||
if (q->fterminal && ! fpty && cmin > 1 && cgot > 0)
|
||
{
|
||
int csleepchars;
|
||
int isleep;
|
||
|
||
/* We don't try to read all the way up to MAX_INPUT,
|
||
since that might drop a character. */
|
||
|
||
if (cmin <= MAX_INPUT - 10)
|
||
csleepchars = cmin;
|
||
else
|
||
csleepchars = MAX_INPUT - 10;
|
||
|
||
isleep = (int) (((long) csleepchars * 10000L) / q->ibaud);
|
||
isleep -= 10;
|
||
|
||
if (isleep > 10)
|
||
{
|
||
struct timeval s;
|
||
|
||
s.tv_sec = isleep / 1000;
|
||
s.tv_usec = (isleep % 1000) * 1000;
|
||
|
||
/* Some versions of select take a pointer to an int,
|
||
while some take a pointer to an fd_set. I just cast
|
||
the arguments to a generic pointer, and assume that
|
||
any machine which distinguishes int * from fd_set *
|
||
(I would be amazed if there are any such machines)
|
||
have an appropriate prototype somewhere or other. */
|
||
(void) select (0, (pointer) NULL, (pointer) NULL,
|
||
(pointer) NULL, &s);
|
||
|
||
/* Here either the select finished sleeping or we got a
|
||
SIGALRM. If the latter occurred, fSalarm was set to
|
||
TRUE; it will be checked at the top of the loop. */
|
||
}
|
||
}
|
||
#endif /* HAVE_BSD_TTY */
|
||
}
|
||
|
||
/* Turn off the pending SIGALRM and return. */
|
||
|
||
usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
|
||
alarm (0);
|
||
usysdep_end_catch ();
|
||
|
||
return fret;
|
||
}
|
||
|
||
/* Read from a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_read (qport, zbuf, pclen, cmin, ctimeout, freport)
|
||
struct sport *qport;
|
||
char *zbuf;
|
||
int *pclen;
|
||
int cmin;
|
||
int ctimeout;
|
||
boolean freport;
|
||
{
|
||
return fsserial_read (&qport->u.sstdin.s.s, zbuf, pclen, cmin, ctimeout,
|
||
freport, qport->u.sstdin.s.fpty);
|
||
}
|
||
|
||
/* Read from a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_read (qport, zbuf, pclen, cmin, ctimeout, freport)
|
||
struct sport *qport;
|
||
char *zbuf;
|
||
int *pclen;
|
||
int cmin;
|
||
int ctimeout;
|
||
boolean freport;
|
||
{
|
||
return fsserial_read (&qport->u.smodem.s.s, zbuf, pclen, cmin, ctimeout,
|
||
freport, FALSE);
|
||
}
|
||
|
||
/* Read from a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_read (qport, zbuf, pclen, cmin, ctimeout, freport)
|
||
struct sport *qport;
|
||
char *zbuf;
|
||
int *pclen;
|
||
int cmin;
|
||
int ctimeout;
|
||
boolean freport;
|
||
{
|
||
return fsserial_read (&qport->u.sdirect.s.s, zbuf, pclen, cmin, ctimeout,
|
||
freport, FALSE);
|
||
}
|
||
|
||
/* Write data to a serial port. */
|
||
|
||
static boolean
|
||
fsserial_write (q, zwrite, cwrite)
|
||
struct ssysdep_serial_port *q;
|
||
const char *zwrite;
|
||
int cwrite;
|
||
{
|
||
int czero;
|
||
|
||
/* We want blocking writes here. */
|
||
if (! fsblock (q, TRUE))
|
||
return FALSE;
|
||
|
||
czero = 0;
|
||
|
||
while (cwrite > 0)
|
||
{
|
||
int cdid;
|
||
|
||
/* If we've received a signal, don't continue. */
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
|
||
/* Loop until we don't get an interrupt. */
|
||
while ((cdid = write (q->owrite, zwrite, cwrite)) < 0
|
||
&& errno == EINTR)
|
||
{
|
||
/* Log the signal. */
|
||
ulog (LOG_ERROR, (const char *) NULL);
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
}
|
||
|
||
if (cdid < 0)
|
||
{
|
||
if (errno != EWOULDBLOCK && errno != EAGAIN)
|
||
{
|
||
ulog (LOG_ERROR, "write: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
cdid = 0;
|
||
}
|
||
|
||
if (cdid == 0)
|
||
{
|
||
/* On some systems write will return 0 if carrier is lost.
|
||
If we fail to write anything ten times in a row, we
|
||
assume that this has happened. This is hacked in like
|
||
this because there seems to be no reliable way to tell
|
||
exactly why the write returned 0. */
|
||
++czero;
|
||
if (czero >= 10)
|
||
{
|
||
ulog (LOG_ERROR, "Line disconnected");
|
||
return FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
czero = 0;
|
||
|
||
cwrite -= cdid;
|
||
zwrite += cdid;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Write to a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_write (qport, zwrite, cwrite)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int cwrite;
|
||
{
|
||
return fsserial_write (&qport->u.sstdin.s.s, zwrite, cwrite);
|
||
}
|
||
|
||
/* Write to a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_write (qport, zwrite, cwrite)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int cwrite;
|
||
{
|
||
return fsserial_write (&qport->u.smodem.s.s, zwrite, cwrite);
|
||
}
|
||
|
||
/* Write to a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_write (qport, zwrite, cwrite)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int cwrite;
|
||
{
|
||
return fsserial_write (&qport->u.sdirect.s.s, zwrite, cwrite);
|
||
}
|
||
|
||
/* The fsysdep_io routine is supposed to both read and write data
|
||
until it has either filled its read buffer or written out all the
|
||
data it was given. This lets us write out large packets without
|
||
losing incoming data. */
|
||
|
||
static boolean
|
||
fsserial_io (q, zwrite, pcwrite, zread, pcread)
|
||
struct ssysdep_serial_port *q;
|
||
const char *zwrite;
|
||
int *pcwrite;
|
||
char *zread;
|
||
int *pcread;
|
||
{
|
||
int cwrite, cread, czero;
|
||
|
||
cwrite = *pcwrite;
|
||
*pcwrite = 0;
|
||
cread = *pcread;
|
||
*pcread = 0;
|
||
|
||
czero = 0;
|
||
|
||
while (TRUE)
|
||
{
|
||
int cgot, cdo, cdid;
|
||
|
||
/* If we've received a signal, don't continue. */
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
|
||
/* This used to always use nonblocking writes, but it turns out
|
||
that some systems don't support them on terminals.
|
||
|
||
The current algorithm is:
|
||
loop:
|
||
unblocked read
|
||
if read buffer full, return
|
||
if nothing to write, return
|
||
if HAVE_UNBLOCKED_WRITES
|
||
write all data
|
||
else
|
||
write up to SINGLE_WRITE bytes
|
||
if all data written, return
|
||
if no data written
|
||
blocked write of up to SINGLE_WRITE bytes
|
||
|
||
This algorithm should work whether the system supports
|
||
unblocked writes on terminals or not. If the system supports
|
||
unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will
|
||
call write more often than it needs to. If the system does
|
||
not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1,
|
||
then the write may hang so long that incoming data is lost.
|
||
This is actually possible at high baud rates on any system
|
||
when a blocking write is done; there is no solution, except
|
||
hardware handshaking. */
|
||
|
||
/* Do an unblocked read. */
|
||
|
||
if (! fsblock (q, FALSE))
|
||
return FALSE;
|
||
|
||
/* Loop until we get something (error or data) other than an
|
||
acceptable EINTR. */
|
||
while ((cgot = read (q->oread, zread, cread)) < 0
|
||
&& errno == EINTR)
|
||
{
|
||
/* Log the signal. */
|
||
ulog (LOG_ERROR, (const char *) NULL);
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
}
|
||
|
||
if (cgot < 0)
|
||
{
|
||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||
{
|
||
ulog (LOG_ERROR, "read: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
cgot = 0;
|
||
}
|
||
|
||
cread -= cgot;
|
||
zread += cgot;
|
||
*pcread += cgot;
|
||
|
||
/* If we've filled the read buffer, or we have nothing left to
|
||
write, return out. */
|
||
|
||
if (cread <= 0 || cwrite <= 0)
|
||
return TRUE;
|
||
|
||
/* The port is currently unblocked. Do a write. */
|
||
|
||
cdo = cwrite;
|
||
|
||
#if ! HAVE_UNBLOCKED_WRITES
|
||
if (cdo > SINGLE_WRITE)
|
||
cdo = SINGLE_WRITE;
|
||
#endif
|
||
|
||
/* Loop until we get something besides EINTR. */
|
||
while ((cdid = write (q->owrite, zwrite, cdo)) < 0
|
||
&& errno == EINTR)
|
||
{
|
||
/* Log the signal. */
|
||
ulog (LOG_ERROR, (const char *) NULL);
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
}
|
||
|
||
if (cdid < 0)
|
||
{
|
||
if (errno != EWOULDBLOCK && errno != EAGAIN)
|
||
{
|
||
ulog (LOG_ERROR, "write: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
cdid = 0;
|
||
}
|
||
|
||
if (cdid > 0)
|
||
{
|
||
/* We wrote some data. If we wrote everything, return out.
|
||
Otherwise loop around and do another read. */
|
||
cwrite -= cdid;
|
||
zwrite += cdid;
|
||
*pcwrite += cdid;
|
||
|
||
if (cwrite <= 0)
|
||
return TRUE;
|
||
|
||
czero = 0;
|
||
}
|
||
else
|
||
{
|
||
/* We didn't write any data. Do a blocking write. */
|
||
|
||
if (! fsblock (q, TRUE))
|
||
return FALSE;
|
||
|
||
cdo = cwrite;
|
||
if (cdo > SINGLE_WRITE)
|
||
cdo = SINGLE_WRITE;
|
||
|
||
DEBUG_MESSAGE1 (DEBUG_PORT,
|
||
"fsserial_io: Blocking write of %d", cdo);
|
||
|
||
/* Loop until we get something besides EINTR. */
|
||
while ((cdid = write (q->owrite, zwrite, cdo)) < 0
|
||
&& errno == EINTR)
|
||
{
|
||
/* Log the signal. */
|
||
ulog (LOG_ERROR, (const char *) NULL);
|
||
if (FGOT_QUIT_SIGNAL ())
|
||
return FALSE;
|
||
}
|
||
|
||
if (cdid < 0)
|
||
{
|
||
ulog (LOG_ERROR, "write: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
|
||
if (cdid == 0)
|
||
{
|
||
/* On some systems write will return 0 if carrier is
|
||
lost. If we fail to write anything ten times in a
|
||
row, we assume that this has happened. This is
|
||
hacked in like this because there seems to be no
|
||
reliable way to tell exactly why the write returned
|
||
0. */
|
||
++czero;
|
||
if (czero >= 10)
|
||
{
|
||
ulog (LOG_ERROR, "Line disconnected");
|
||
return FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cwrite -= cdid;
|
||
zwrite += cdid;
|
||
*pcwrite += cdid;
|
||
czero = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* I/O to a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_io (qport, zwrite, pcwrite, zread, pcread)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int *pcwrite;
|
||
char *zread;
|
||
int *pcread;
|
||
{
|
||
return fsserial_io (&qport->u.sstdin.s.s, zwrite, pcwrite, zread, pcread);
|
||
}
|
||
|
||
/* I/O to a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_io (qport, zwrite, pcwrite, zread, pcread)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int *pcwrite;
|
||
char *zread;
|
||
int *pcread;
|
||
{
|
||
return fsserial_io (&qport->u.smodem.s.s, zwrite, pcwrite, zread, pcread);
|
||
}
|
||
|
||
/* I/O to a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_io (qport, zwrite, pcwrite, zread, pcread)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int *pcwrite;
|
||
char *zread;
|
||
int *pcread;
|
||
{
|
||
return fsserial_io (&qport->u.sdirect.s.s, zwrite, pcwrite, zread, pcread);
|
||
}
|
||
|
||
/* Send a break character to a serial port. */
|
||
|
||
static boolean
|
||
fsserial_break (q)
|
||
struct ssysdep_serial_port *q;
|
||
{
|
||
#if HAVE_BSD_TTY
|
||
ioctl (q->owrite, TIOCSBRK, 0);
|
||
sleep (1);
|
||
ioctl (q->owrite, TIOCCBRK, 0);
|
||
return TRUE;
|
||
#endif /* HAVE_BSD_TTY */
|
||
#if HAVE_SYSV_TERMIO
|
||
ioctl (q->owrite, TCSBRK, 0);
|
||
return TRUE;
|
||
#endif /* HAVE_SYSV_TERMIO */
|
||
#if HAVE_POSIX_TERMIOS
|
||
return tcsendbreak (q->owrite, 0) == 0;
|
||
#endif /* HAVE_POSIX_TERMIOS */
|
||
}
|
||
|
||
/* Send a break character to a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_break (qport)
|
||
struct sport *qport;
|
||
{
|
||
return fsserial_break (&qport->u.sstdin.s.s);
|
||
}
|
||
|
||
/* Send a break character to a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_break (qport)
|
||
struct sport *qport;
|
||
{
|
||
return fsserial_break (&qport->u.smodem.s.s);
|
||
}
|
||
|
||
/* Send a break character to a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_break (qport)
|
||
struct sport *qport;
|
||
{
|
||
return fsserial_break (&qport->u.sdirect.s.s);
|
||
}
|
||
|
||
/* Change the setting of a serial port. */
|
||
|
||
static boolean
|
||
fsserial_set (q, tset)
|
||
struct ssysdep_serial_port *q;
|
||
enum tportsetting tset;
|
||
{
|
||
if (! q->fterminal)
|
||
return TRUE;
|
||
|
||
switch (tset)
|
||
{
|
||
case PORTSETTING_EIGHT:
|
||
#if HAVE_BSD_TTY
|
||
if (q->snew.sg_flags == (RAW | ANYP))
|
||
return TRUE;
|
||
q->snew.sg_flags = RAW | ANYP;
|
||
#endif
|
||
#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
|
||
if ((q->snew.c_iflag & ICLEAR_IFLAG) == 0)
|
||
return TRUE;
|
||
q->snew.c_iflag &=~ ICLEAR_IFLAG;
|
||
#endif
|
||
if (! fsetterminfodrain (q->oread, &q->snew))
|
||
{
|
||
ulog (LOG_ERROR, "Can't go to raw mode: %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
|
||
case PORTSETTING_SEVEN:
|
||
#if HAVE_BSD_TTY
|
||
if (q->snew.sg_flags == (CBREAK | ANYP | TANDEM))
|
||
return TRUE;
|
||
q->snew.sg_flags = CBREAK | ANYP | TANDEM;
|
||
#endif /* HAVE_BSD_TTY */
|
||
#if HAVE_SYSV_TERMIO | HAVE_POSIX_TERMIOS
|
||
{
|
||
int iwant;
|
||
|
||
#ifdef CRTSCTS
|
||
/* It would be nice to do this is in a more portable fashion,
|
||
but in any case this is apparently correct for SunOS. If
|
||
we are doing hardware flow control, we don't also send
|
||
start and stop characters; however, we do recognize
|
||
incoming start and stop characters. */
|
||
if ((q->snew.c_cflag & CRTSCTS) != 0)
|
||
iwant = ISTRIP | IXON;
|
||
else
|
||
iwant = ISTRIP | IXON | IXOFF;
|
||
#else /* ! defined (CRTSCTS) */
|
||
iwant = ISTRIP | IXON | IXOFF;
|
||
#endif /* ! defined (CRTSCTS) */
|
||
|
||
if ((q->snew.c_iflag & ICLEAR_IFLAG) == iwant)
|
||
return TRUE;
|
||
|
||
q->snew.c_iflag &=~ ICLEAR_IFLAG;
|
||
q->snew.c_iflag |= iwant;
|
||
}
|
||
#endif /* HAVE_SYSV_TERMIO | HAVE_POSIX_TERMIOS */
|
||
|
||
if (! fsetterminfodrain (q->oread, &q->snew))
|
||
{
|
||
ulog (LOG_ERROR, "Can't go to seven bit mode: %s",
|
||
strerror (errno));
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
|
||
default:
|
||
#if DEBUG > 0
|
||
ulog (LOG_FATAL, "fsserial_set: Can't happen");
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
/* Change settings of a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_set (qport, tset)
|
||
struct sport *qport;
|
||
enum tportsetting tset;
|
||
{
|
||
return fsserial_set (&qport->u.sstdin.s.s, tset);
|
||
}
|
||
|
||
/* Change settings of a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_set (qport, tset)
|
||
struct sport *qport;
|
||
enum tportsetting tset;
|
||
{
|
||
return fsserial_set (&qport->u.smodem.s.s, tset);
|
||
}
|
||
|
||
/* Change settings of a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_set (qport, tset)
|
||
struct sport *qport;
|
||
enum tportsetting tset;
|
||
{
|
||
return fsserial_set (&qport->u.sdirect.s.s, tset);
|
||
}
|
||
|
||
/* Run a chat program. */
|
||
|
||
static boolean
|
||
fsrun_chat (oread, owrite, zprog)
|
||
int oread;
|
||
int owrite;
|
||
const char *zprog;
|
||
{
|
||
int cargs;
|
||
const char **azargs;
|
||
char *zcopy, *zarg;
|
||
int aidescs[3];
|
||
FILE *e;
|
||
pid_t ipid;
|
||
char *z;
|
||
|
||
/* Get the arguments into an array to pass to isspawn. */
|
||
zcopy = (char *) alloca (strlen (zprog) + 1);
|
||
strcpy (zcopy, zprog);
|
||
cargs = 0;
|
||
for (zarg = strtok (zcopy, " \t");
|
||
zarg != NULL;
|
||
zarg = strtok ((char *) NULL, " \t"))
|
||
++cargs;
|
||
|
||
azargs = (const char **) alloca ((cargs + 1) * sizeof (const char *));
|
||
|
||
strcpy (zcopy, zprog);
|
||
cargs = 0;
|
||
for (zarg = strtok (zcopy, " \t");
|
||
zarg != NULL;
|
||
zarg = strtok ((char *) NULL, " \t"))
|
||
{
|
||
azargs[cargs] = zarg;
|
||
++cargs;
|
||
}
|
||
azargs[cargs] = NULL;
|
||
|
||
aidescs[0] = oread;
|
||
aidescs[1] = owrite;
|
||
aidescs[2] = SPAWN_READ_PIPE;
|
||
|
||
/* Pass fkeepuid, fkeepenv and fshell as TRUE. This puts the
|
||
responsibility of maintaing security on the chat program. */
|
||
ipid = isspawn (azargs, aidescs, TRUE, TRUE, (const char *) NULL,
|
||
FALSE, TRUE, (const char *) NULL,
|
||
(const char *) NULL, (const char *) NULL);
|
||
if (ipid < 0)
|
||
{
|
||
ulog (LOG_ERROR, "isspawn (%s): %s", azargs[0], strerror (errno));
|
||
return FALSE;
|
||
}
|
||
|
||
e = fdopen (aidescs[2], (char *) "r");
|
||
if (e == NULL)
|
||
{
|
||
ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
|
||
(void) close (aidescs[2]);
|
||
(void) kill (ipid, SIGKILL);
|
||
(void) iswait ((unsigned long) ipid, (const char *) NULL);
|
||
return FALSE;
|
||
}
|
||
|
||
/* The FILE e now is attached to stderr of the program. Forward
|
||
every line the program outputs to the log file. */
|
||
while ((z = zfgets (e, FALSE)) != NULL)
|
||
{
|
||
int clen;
|
||
|
||
clen = strlen (z);
|
||
if (z[clen - 1] == '\n')
|
||
z[clen - 1] = '\0';
|
||
if (*z != '\0')
|
||
ulog (LOG_NORMAL, "chat: %s", z);
|
||
xfree ((pointer) z);
|
||
}
|
||
|
||
(void) fclose (e);
|
||
|
||
return iswait ((unsigned long) ipid, "Chat program") == 0;
|
||
}
|
||
|
||
/* Run a chat program on a stdin port. */
|
||
|
||
boolean
|
||
fsysdep_stdin_chat (qport, zprog)
|
||
struct sport *qport;
|
||
const char *zprog;
|
||
{
|
||
return fsrun_chat (qport->u.sstdin.s.s.oread,
|
||
qport->u.sstdin.s.s.owrite,
|
||
zprog);
|
||
}
|
||
|
||
/* Run a chat program on a modem port. */
|
||
|
||
boolean
|
||
fsysdep_modem_chat (qport, zprog)
|
||
struct sport *qport;
|
||
const char *zprog;
|
||
{
|
||
return fsrun_chat (qport->u.smodem.s.s.oread,
|
||
qport->u.smodem.s.s.owrite,
|
||
zprog);
|
||
}
|
||
|
||
/* Run a chat program on a direct port. */
|
||
|
||
boolean
|
||
fsysdep_direct_chat (qport, zprog)
|
||
struct sport *qport;
|
||
const char *zprog;
|
||
{
|
||
return fsrun_chat (qport->u.sdirect.s.s.oread,
|
||
qport->u.sdirect.s.s.owrite,
|
||
zprog);
|
||
}
|
||
|
||
#if HAVE_TCP
|
||
|
||
/* Run a chat program on a TCP port. */
|
||
|
||
boolean
|
||
fsysdep_tcp_chat (qport, zprog)
|
||
struct sport *qport;
|
||
const char *zprog;
|
||
{
|
||
return fsrun_chat (qport->u.stcp.o, qport->u.stcp.o, zprog);
|
||
}
|
||
|
||
#endif /* HAVE_TCP */
|
||
|
||
/* Functions to return baud rates. */
|
||
|
||
/* Return baud rate of a stdin port. */
|
||
|
||
long
|
||
isysdep_stdin_baud (qport)
|
||
struct sport *qport;
|
||
{
|
||
return qport->u.sstdin.s.s.ibaud;
|
||
}
|
||
|
||
/* Return baud rate of a modem port. */
|
||
|
||
long
|
||
isysdep_modem_baud (qport)
|
||
struct sport *qport;
|
||
{
|
||
return qport->u.smodem.s.s.ibaud;
|
||
}
|
||
|
||
/* Return baud rate of a direct port. */
|
||
|
||
long
|
||
isysdep_direct_baud (qport)
|
||
struct sport *qport;
|
||
{
|
||
return qport->u.sdirect.s.s.ibaud;
|
||
}
|
||
|
||
#if HAVE_TCP
|
||
|
||
/* Some system dependent routines for TCP ports. These work by
|
||
setting up an ssysdep_serial_port structure to fake out the serial
|
||
port routines. I'm doing it this way to avoid having to write the
|
||
complicated timeout code twice, and because the serial port code
|
||
will work fine. It does mean that if the serial port code changes
|
||
this code will have to be considered. */
|
||
|
||
/* Read data from a TCP port. */
|
||
|
||
boolean
|
||
fsysdep_tcp_read (qport, zread, pclen, cmin, ctimeout, freport)
|
||
struct sport *qport;
|
||
char *zread;
|
||
int *pclen;
|
||
int cmin;
|
||
int ctimeout;
|
||
boolean freport;
|
||
{
|
||
struct ssysdep_serial_port s;
|
||
|
||
s.oread = s.owrite = qport->u.stcp.o;
|
||
s.fread_blocking = TRUE;
|
||
s.fterminal = FALSE;
|
||
return fsserial_read (&s, zread, pclen, cmin, ctimeout, freport, FALSE);
|
||
}
|
||
|
||
/* Write data to a TCP port. */
|
||
|
||
boolean
|
||
fsysdep_tcp_write (qport, zwrite, cwrite)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int cwrite;
|
||
{
|
||
struct ssysdep_serial_port s;
|
||
|
||
s.oread = s.owrite = qport->u.stcp.o;
|
||
s.fread_blocking = TRUE;
|
||
s.fterminal = FALSE;
|
||
return fsserial_write (&s, zwrite, cwrite);
|
||
}
|
||
|
||
/* Read and write data to and from a TCP port. We actually don't
|
||
bother to really implement this, since the system will buffer up
|
||
plenty of TCP data (only 256 bytes are buffered for a terminal,
|
||
so losing data becomes a real possibility). */
|
||
|
||
boolean
|
||
fsysdep_tcp_io (qport, zwrite, pcwrite, zread, pcread)
|
||
struct sport *qport;
|
||
const char *zwrite;
|
||
int *pcwrite;
|
||
char *zread;
|
||
int *pcread;
|
||
{
|
||
struct ssysdep_serial_port s;
|
||
|
||
s.oread = s.owrite = qport->u.stcp.o;
|
||
s.fread_blocking = TRUE;
|
||
s.fterminal = FALSE;
|
||
*pcread = 0;
|
||
return fsserial_write (&s, zwrite, *pcwrite);
|
||
}
|
||
|
||
#endif /* HAVE_TCP */
|
||
|
||
/*
|
||
Local variables:
|
||
mode:c
|
||
End:
|
||
*/
|