xref: /386bsd/usr/src/libexec/uucp/sys2.c (revision a2142627)
1 /* sys2.unx
2    The system dependent communication routines for UNIX.
3 
4    Copyright (C) 1991, 1992 Ian Lance Taylor
5 
6    This file is part of the Taylor UUCP package.
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22    The author of the program may be contacted at ian@airs.com or
23    c/o AIRS, P.O. Box 520, Waltham, MA 02254.
24 
25    $Log: sys2.unx,v $
26    Revision 1.72  1992/04/03  17:43:39  ian
27    Petri Helenius: don't clobber undefined bits in termio or termios
28 
29    Revision 1.71  1992/04/01  21:52:04  ian
30    T. William Wells: handle a system without <poll.h> or <stropts.h>
31 
32    Revision 1.70  1992/03/30  15:29:58  ian
33    Added HAVE_SVR4_LOCKFILES
34 
35    Revision 1.69  1992/03/29  22:25:27  ian
36    Always block and unblock read and write descriptors together
37 
38    Revision 1.68  1992/03/28  04:12:17  ian
39    Gerben Wierda: minor cleanups
40 
41    Revision 1.67  1992/03/28  03:06:04  ian
42    Don't use TIOCEXCL locking
43 
44    Revision 1.66  1992/03/28  02:47:30  ian
45    Rework HAVE_UNBLOCKED_WRITES to work even if writes are unblocked
46 
47    Revision 1.65  1992/03/17  15:35:28  ian
48    Log signals when they happen, even if we continue looping
49 
50    Revision 1.64  1992/03/17  05:01:33  ian
51    Don't block when opening the write descriptor
52 
53    Revision 1.63  1992/03/17  01:03:03  ian
54    Miscellaneous cleanup
55 
56    Revision 1.62  1992/03/16  01:23:08  ian
57    Make blocking writes optional
58 
59    Revision 1.61  1992/03/15  07:15:42  ian
60    T. William Wells: don't use unblocked writes
61 
62    Revision 1.60  1992/03/15  04:51:17  ian
63    Keep an array of signals we've received rather than a single variable
64 
65    Revision 1.59  1992/03/15  01:54:46  ian
66    All execs are now done in isspawn, all waits are done in iswait
67 
68    Revision 1.58  1992/03/12  21:50:50  ian
69    Moved local header includes above sleep routine determination
70 
71    Revision 1.57  1992/03/12  19:54:43  ian
72    Debugging based on types rather than number
73 
74    Revision 1.56  1992/03/11  02:09:57  ian
75    Franc,ois Pinard: retry fork several times before giving up
76 
77    Revision 1.55  1992/03/09  22:11:46  ian
78    Franc,ois Pinard: sleep for a second after closing a serial port
79 
80    Revision 1.54  1992/03/09  22:07:36  ian
81    Wait for terminal output to drain at various points
82 
83    Revision 1.53  1992/03/08  16:56:51  ian
84    Ted Lindgreen: if CRTSCTS is defined, don't turn on IXOFF
85 
86    Revision 1.52  1992/03/08  04:56:21  ian
87    Peter da Silva: added ``lockname'' command for ports
88 
89    Revision 1.51  1992/03/08  01:56:01  ian
90    Include <sys/ioctl.h> if we have it
91 
92    Revision 1.50  1992/03/08  01:37:45  ian
93    Suppurt TIOCEXCL locking
94 
95    Revision 1.49  1992/03/07  16:25:21  ian
96    Preserve unknown bits in c_cflag
97 
98    Revision 1.48  1992/03/04  23:43:39  ian
99    Petri Helenius: didn't remove lock file if open failed
100 
101    Revision 1.47  1992/03/04  01:40:51  ian
102    Thomas Fischer: tweaked a bit for the NeXT
103 
104    Revision 1.46  1992/03/03  21:01:20  ian
105    Use strict timeout in fsserial_read, eliminate all race conditions
106 
107    Revision 1.45  1992/03/03  04:25:00  ian
108    T. William Wells: don't arbitrarily extend read timeout
109 
110    Revision 1.44  1992/03/02  04:53:07  ian
111    Marc Unangst: added HAVE_SCO_LOCKFILES configuration parameter
112 
113    Revision 1.43  1992/02/28  05:06:15  ian
114    T. William Wells: fsysdep_catch must be a macro
115 
116    Revision 1.42  1992/02/27  05:40:54  ian
117    T. William Wells: detach from controlling terminal, handle signals safely
118 
119    Revision 1.41  1992/02/24  21:22:47  ian
120    The poll function takes milliseconds, not microseconds (my error)
121 
122    Revision 1.40  1992/02/24  21:18:17  ian
123    Roberto Biancardi: use poll for sleeping if we haven't got anything else
124 
125    Revision 1.39  1992/02/24  20:07:43  ian
126    John Theus: some systems don't have <fcntl.h>
127 
128    Revision 1.38  1992/02/23  03:26:51  ian
129    Overhaul to use automatic configure shell script
130 
131    Revision 1.37  1992/02/17  22:08:50  ian
132    Bob Denny: log chat script messages as LOG_NORMAL, not LOG_ERROR
133 
134    Revision 1.36  1992/02/08  20:02:36  ian
135    Added HAVE_SETRET configuration option for systems without setjmp
136 
137    Revision 1.35  1992/02/08  03:54:18  ian
138    Include <string.h> only in <uucp.h>, added 1992 copyright
139 
140    Revision 1.34  1992/01/16  16:32:44  ian
141    Mike Park: ioctl is sometimes declared varadic, so we can't declare it
142 
143    Revision 1.33  1992/01/15  21:06:11  ian
144    Mike Park: some systems can't include <sys/time.h> and <time.h> together
145 
146    Revision 1.32  1992/01/15  20:40:04  ian
147    Mike Park: some systems don't have <limits.h>
148 
149    Revision 1.31  1992/01/15  19:40:35  ian
150    Mike Park: handle HAVE_UNION_WAIT correctly and completely
151 
152    Revision 1.30  1992/01/14  04:18:47  ian
153    Chip Salzenberg: added HAVE_USLEEP configuration parameter
154 
155    Revision 1.29  1992/01/13  06:11:39  ian
156    David Nugent: can't declare open or fcntl
157 
158    Revision 1.28  1991/12/31  04:16:19  ian
159    Chip Salzenberg: don't turn on IXON and IXOFF at the start
160 
161    Revision 1.27  1991/12/29  04:04:18  ian
162    Added a bunch of extern definitions
163 
164    Revision 1.26  1991/12/29  00:55:23  ian
165    Monty Solomon: added HAVE_UNION_WAIT
166 
167    Revision 1.25  1991/12/22  22:14:19  ian
168    Monty Solomon: added HAVE_UNISTD_H configuration parameter
169 
170    Revision 1.24  1991/12/20  02:23:10  ian
171    Don't change port settings if we don't have to
172 
173    Revision 1.23  1991/12/19  04:25:57  ian
174    Terry Gardner: configuration parameter to not use both NONBLOCK and NDELAY
175 
176    Revision 1.22  1991/12/17  23:14:08  ian
177    T. William Wells: allow dialer complete and abort to be chat scripts
178 
179    Revision 1.21  1991/12/17  22:31:15  ian
180    Start in RAW mode, to avoid dropping characters when we switch to it
181 
182    Revision 1.20  1991/12/17  05:24:01  ian
183    David Nugent: flush pending input in fsserial_open
184 
185    Revision 1.19  1991/12/15  04:28:23  ian
186    Don't turn on ISTRIP initially
187 
188    Revision 1.18  1991/12/10  19:45:05  ian
189    Added ulog_device to record device name for log file
190 
191    Revision 1.17  1991/12/01  02:23:12  ian
192    Niels Baggesen: don't multiply include <unistd.h>
193 
194    Revision 1.16  1991/11/26  01:50:30  ian
195    Set fread_blocking and fwrite_blocking correctly for TCP routines
196 
197    Revision 1.15  1991/11/26  01:45:42  ian
198    Marty Shannon: configuration option to not include <sys/wait.h>
199 
200    Revision 1.14  1991/11/22  06:05:57  ian
201    Gregory Gulik: fix wait status macro definitions
202 
203    Revision 1.13  1991/11/21  20:58:18  ian
204    Brian Campbell: for HAVE_SIGSETJMP use sigjmp_buf, not jmp_buf
205 
206    Revision 1.12  1991/11/15  23:13:53  ian
207    Fixed termio(s) version of fsserial_set
208 
209    Revision 1.11  1991/11/13  20:38:00  ian
210    Added TCP port type for connections over TCP
211 
212    Revision 1.10  1991/11/12  19:07:27  ian
213    Be careful to only call fsetterminfo on a terminal
214 
215    Revision 1.9  1991/11/11  23:47:24  ian
216    Added chat-program to run a program to do a chat script
217 
218    Revision 1.8  1991/11/11  00:39:45  ian
219    Open port in seven bit mode, added fport_set to change to eight bit
220 
221    Revision 1.7  1991/11/08  22:52:34  ian
222    Brian Campbell: only include <sys/time.h> and <sys/ioctl.h> when needed
223 
224    Revision 1.6  1991/11/08  22:11:45  ian
225    Brian Campbell: allow sigsetjmp as configuration option
226 
227    Revision 1.5  1991/11/07  22:52:11  ian
228    Chip Salzenberg: force stdin and stdout to stay open in case of spawning
229 
230    Revision 1.4  1991/11/07  21:43:59  ian
231    Chip Salzenberg: set terminal modes directly, don't or them in
232 
233    Revision 1.3  1991/11/07  19:42:16  ian
234    Chip Salzenberg: declare inline functions consistently
235 
236    Revision 1.2  1991/11/07  19:32:28  ian
237    Chip Salzenberg: allow LOCKDIR, and check that locking process exists
238 
239    Revision 1.1  1991/09/10  19:45:50  ian
240    Initial revision
241 
242    */
243 
244 #include "uucp.h"
245 
246 #if USE_RCS_ID
247 char sys2_unx_rcsid[] = "$Id: sys2.unx,v 1.72 1992/04/03 17:43:39 ian Rel $";
248 #endif
249 
250 #include <errno.h>
251 
252 #if HAVE_LIMITS_H
253 #include <limits.h>
254 #endif
255 
256 #if USE_STDIO && HAVE_UNISTD_H
257 #include <unistd.h>
258 #endif
259 
260 #include "system.h"
261 #include "sysdep.h"
262 #include "port.h"
263 
264 /* Pick a timing routine to use.  I somewhat arbitrarily picked usleep
265    above nap above napms above poll above select.  */
266 
267 #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
268 #define USE_SELECT_TIMER 0
269 #else
270 #define USE_SELECT_TIMER HAVE_SELECT
271 #endif
272 
273 #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
274 #undef HAVE_POLL
275 #define HAVE_POLL 0
276 #endif
277 
278 #if HAVE_USLEEP || HAVE_NAP
279 #undef HAVE_NAPMS
280 #define HAVE_NAPMS 0
281 #endif
282 
283 #if HAVE_USLEEP
284 #undef HAVE_NAP
285 #define HAVE_NAP 0
286 #endif
287 
288 #if HAVE_FCNTL_H
289 #include <fcntl.h>
290 #else
291 #if HAVE_SYS_FILE_H
292 #include <sys/file.h>
293 #endif
294 #endif
295 
296 #ifndef O_RDONLY
297 #define O_RDONLY 0
298 #define O_WRONLY 1
299 #define O_RDWR 2
300 #endif
301 
302 #if HAVE_SYS_IOCTL_H
303 #include <sys/ioctl.h>
304 #endif
305 
306 #if USE_SELECT_TIMER || HAVE_BSD_TTY
307 #include <sys/time.h>
308 #endif
309 
310 #if HAVE_POLL
311 #if HAVE_STROPTS_H
312 #include <stropts.h>
313 #endif
314 #if HAVE_POLL_H
315 #include <poll.h>
316 #endif
317 #if ! HAVE_STROPTS_H && ! HAVE_POLL_H
318 /* We need a definition for struct pollfd, although it doesn't matter
319    what it contains.  It's used in usysdep_pause.  */
320 struct pollfd
321 {
322   int idummy;
323 };
324 #endif /* ! HAVE_STROPTS_H && ! HAVE_POLL_H */
325 #endif /* HAVE_POLL */
326 
327 #if HAVE_TIME_H
328 #if HAVE_SYS_TIME_AND_TIME_H || (! USE_SELECT_TIMER && ! HAVE_BSD_TTY)
329 #include <time.h>
330 #endif
331 #endif
332 
333 /* Get definitions for both O_NONBLOCK and O_NDELAY.  */
334 
335 #ifndef O_NDELAY
336 #ifdef FNDELAY
337 #define O_NDELAY FNDELAY
338 #else /* ! defined (FNDELAY) */
339 #define O_NDELAY 0
340 #endif /* ! defined (FNDELAY) */
341 #endif /* ! defined (O_NDELAY) */
342 
343 #ifndef O_NONBLOCK
344 #ifdef FNBLOCK
345 #define O_NONBLOCK FNBLOCK
346 #else /* ! defined (FNBLOCK) */
347 #define O_NONBLOCK 0
348 #endif /* ! defined (FNBLOCK) */
349 #endif /* ! defined (O_NONBLOCK) */
350 
351 #if O_NDELAY == 0 && O_NONBLOCK == 0
352  #error No way to do nonblocking I/O
353 #endif
354 
355 /* If we can define them both together, do so.  This is because some
356    ancient drivers on some systems appear to look for one but not the
357    other.  Otherwise just use O_NONBLOCK.  */
358 #if COMBINED_UNBLOCK
359 #define FILE_UNBLOCKED (O_NDELAY | O_NONBLOCK)
360 #else
361 #define FILE_UNBLOCKED O_NONBLOCK
362 #endif
363 
364 /* Get definitions for both EAGAIN and EWOULDBLOCK.  */
365 
366 #ifndef EAGAIN
367 #ifndef EWOULDBLOCK
368 #define EAGAIN (-1)
369 #define EWOULDBLOCK (-1)
370 #else /* defined (EWOULDBLOCK) */
371 #define EAGAIN EWOULDBLOCK
372 #endif /* defined (EWOULDBLOCK) */
373 #else /* defined (EAGAIN) */
374 #ifndef EWOULDBLOCK
375 #define EWOULDBLOCK EAGAIN
376 #endif /* ! defined (EWOULDBLOCK) */
377 #endif /* defined (EAGAIN) */
378 
379 /* Make sure we have a definition for MAX_INPUT.  */
380 
381 #ifndef MAX_INPUT
382 #define MAX_INPUT (256)
383 #endif
384 
385 /* Make sure we have definitions for major and minor.  */
386 
387 #ifndef major
388 #define major(i) (((i) >> 8) & 0xff)
389 #endif
390 #ifndef minor
391 #define minor(i) ((i) & 0xff)
392 #endif
393 
394 /* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal.
395    Otherwise, if we have the TIOCEXCL ioctl call, we have to open the
396    terminal before we know that it is unlocked.  */
397 #ifdef TIOCSINUSE
398 #define HAVE_TIOCSINUSE 1
399 #else
400 #ifdef TIOCEXCL
401 #define HAVE_TIOCEXCL 1
402 #endif
403 #endif
404 
405 /* Determine bits to clear for the various terminal control fields for
406    HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS.  */
407 
408 #if HAVE_SYSV_TERMIO
409 #define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
410 		      | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
411 		      | IXON | IXANY | IXOFF)
412 #define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
413 		      | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
414 		      | VTDLY | FFDLY)
415 #define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD)
416 #define ISET_CFLAG (CS8 | CREAD | HUPCL)
417 #define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
418 		      | ECHONL | NOFLSH)
419 #endif
420 #if HAVE_POSIX_TERMIOS
421 #define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
422 		      | INLCR | INPCK | ISTRIP | IXOFF | IXON \
423 		      | PARMRK)
424 #define ICLEAR_OFLAG (OPOST)
425 #define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD)
426 #define ISET_CFLAG (CS8 | CREAD | HUPCL)
427 #define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
428 		      | ISIG | NOFLSH | TOSTOP)
429 #endif
430 
431 /* External functions.  */
432 extern char *strlwr ();
433 extern int close (), pipe (), dup2 (), read (), write ();
434 extern int fclose ();
435 extern void _exit ();
436 #if USE_SELECT_TIMER || HAVE_BSD_TTY
437 extern int select ();
438 #endif
439 #if HAVE_NAP
440 extern int nap ();
441 #endif
442 #if HAVE_NAPMS
443 extern int napms ();
444 #endif
445 #if HAVE_POLL
446 extern int poll ();
447 #endif
448 
449 /* Local functions.  */
450 
451 static SIGtype usalarm P((int isig));
452 static boolean fsserial_lockfile P((boolean flok, const struct sport *,
453 				    const char *zdevice));
454 static boolean fsserial_lock P((const struct sport *qport,
455 				struct ssysdep_serial_port *q,
456 				boolean fin, const char *zdevice));
457 static boolean fsserial_open P((const char *z, long ibaud, boolean fwait,
458 				struct ssysdep_serial_port *q));
459 __inline__ static boolean fsblock P((struct ssysdep_serial_port *q,
460 				     boolean fblock));
461 static boolean fsserial_close P((struct ssysdep_serial_port *q));
462 static boolean fsserial_reset P((struct ssysdep_serial_port *q));
463 static boolean fsserial_read P((struct ssysdep_serial_port *q,
464 				char *zbuf, int *pclen, int cmin,
465 				int ctimeout, boolean freport,
466 				boolean fpty));
467 static boolean fsserial_write P((struct ssysdep_serial_port *q,
468 				 const char *zwrite, int cwrite));
469 static boolean fsserial_io P((struct ssysdep_serial_port *q,
470 			      const char *zwrite, int *pcwrite,
471 			      char *zread, int *pcread));
472 static boolean fsserial_break P((struct ssysdep_serial_port *q));
473 static boolean fsserial_set P((struct ssysdep_serial_port *q,
474 			       enum tportsetting tset));
475 static boolean fsrun_chat P((int oread, int owrite, const char *zprog));
476 
477 /* This code handles SIGALRM.  See the discussion above fsserial_read.
478    Normally we ignore SIGALRM, but the handler will temporarily be set
479    to this function, which should set fSalarm and then either longjmp
480    or schedule another SIGALRM.  fSalarm is never referred to outside
481    of this file, but we don't make it static to try to fool compilers
482    which don't understand volatile.  */
483 
484 volatile sig_atomic_t fSalarm;
485 
486 static SIGtype
487 usalarm (isig)
488      int isig;
489 {
490 #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
491   (void) signal (isig, usalarm);
492 #endif
493 
494   fSalarm = TRUE;
495 
496 #if HAVE_RESTARTABLE_SYSCALLS
497   longjmp (sSjmp_buf, 1);
498 #else
499   alarm (1);
500 #endif
501 }
502 
503 /* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and
504    SIGPIPE and another to restore the original state.  When these
505    functions are called (in fsysdep_modem_close) SIGHUP is being
506    ignored.  The routines are isblocksigs, which returns a value of
507    type HELD_SIG_MASK and usunblocksigs which takes a single argument
508    of type HELD_SIG_MASK.  */
509 
510 #if HAVE_SIGPROCMASK
511 
512 /* Use the POSIX sigprocmask call.  */
513 
514 extern int sigprocmask ();
515 
516 #define HELD_SIG_MASK sigset_t
517 
518 static sigset_t isblocksigs P((void));
519 
520 static sigset_t
521 isblocksigs ()
522 {
523   sigset_t sblock, sold;
524 
525   sigemptyset (&sblock);
526   sigaddset (&sblock, SIGINT);
527   sigaddset (&sblock, SIGQUIT);
528   sigaddset (&sblock, SIGTERM);
529   sigaddset (&sblock, SIGPIPE);
530   sigprocmask (SIG_BLOCK, &sblock, &sold);
531   return sold;
532 }
533 
534 #define usunblocksigs(s) \
535   ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL))
536 
537 #else /* ! HAVE_SIGPROCMASK */
538 #if HAVE_SIGBLOCK
539 
540 /* Use the BSD sigblock and sigsetmask calls.  */
541 
542 extern int sigblock (), sigsetmask ();
543 
544 #define HELD_SIG_MASK int
545 
546 #ifndef sigmask
547 #define sigmask(i) (1 << ((i) - 1))
548 #endif
549 
550 #define isblocksigs() \
551   sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \
552 	    | sigmask (SIGTERM) | sigmask (SIGPIPE))
553 
554 #define usunblocksigs(i) ((void) sigsetmask (i))
555 
556 #else /* ! HAVE_SIGBLOCK */
557 
558 #if HAVE_SIGHOLD
559 
560 /* Use the SVR3 sighold and sigrelse calls.  */
561 
562 extern int sighold (), sigrelse ();
563 
564 #define HELD_SIG_MASK int
565 
566 static int isblocksigs P((void));
567 
568 static int
569 isblocksigs ()
570 {
571   sighold (SIGINT);
572   sighold (SIGQUIT);
573   sighold (SIGTERM);
574   sighold (SIGPIPE);
575   return 0;
576 }
577 
578 static void usunblocksigs P((int));
579 
580 /*ARGSUSED*/
581 static void
582 usunblocksigs (i)
583      int i;
584 {
585   sigrelse (SIGINT);
586   sigrelse (SIGQUIT);
587   sigrelse (SIGTERM);
588   sigrelse (SIGPIPE);
589 }
590 
591 #else /* ! HAVE_SIGHOLD */
592 
593 /* We have no way to block signals.  This system will suffer from a
594    race condition in fsysdep_modem_close.  */
595 
596 #define HELD_SIG_MASK int
597 
598 #define isblocksigs() 0
599 
600 #define usunblocksigs(i)
601 
602 #endif /* ! HAVE_SIGHOLD */
603 #endif /* ! HAVE_SIGBLOCK */
604 #endif /* ! HAVE_SIGPROCMASK */
605 
606 /* Pause for half a second.  This doesn't really belong in this file,
607    but all the timing routines are here.  */
608 
609 void
610 usysdep_pause ()
611 {
612 #if HAVE_NAPMS
613   napms (500);
614 #endif /* HAVE_NAPMS */
615 #if HAVE_NAP
616   nap (500L);
617 #endif /* HAVE_NAP */
618 #if HAVE_USLEEP
619   usleep (500 * (long) 1000);
620 #endif /* HAVE_USLEEP */
621 #if HAVE_POLL
622   struct pollfd sdummy;
623 
624   /* We need to pass an unused pollfd structure because poll checks
625      the address before checking the number of elements.  */
626   poll (&sdummy, 0, 500);
627 #endif /* HAVE_POLL */
628 #if USE_SELECT_TIMER
629   struct timeval s;
630 
631   s.tv_sec = 0;
632   s.tv_usec = 500 * (long) 1000;
633   select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s);
634 #endif /* USE_SELECT_TIMER */
635 #if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP
636 #if ! USE_SELECT_TIMER && ! HAVE_POLL
637   sleep (1);
638 #endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */
639 #endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */
640 }
641 
642 /* This routine is used for both locking and unlocking.  It is the
643    only routine which knows how to translate a device name into the
644    name of a lock file.  If it can't figure out a name, it does
645    nothing and returns TRUE.  */
646 
647 static boolean
648 fsserial_lockfile (flok, qport, zdevice)
649      boolean flok;
650      const struct sport *qport;
651      const char *zdevice;
652 {
653   const char *z;
654 
655   z = qport->zlockname;
656   if (z == NULL)
657     {
658       char *zalc;
659 
660       z = zdevice;
661       if (z == NULL)
662 	{
663 	  z = qport->zname;
664 	  if (z == NULL)
665 	    return TRUE;
666 	}
667 
668 #if ! HAVE_SVR4_LOCKFILES
669       if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0)
670 	z += sizeof "/dev/" - 1;
671       zalc = (char *) alloca (strlen (z) + sizeof "LCK..");
672       sprintf (zalc, "LCK..%s", z);
673 #if HAVE_SCO_LOCKFILES
674       strlwr (zalc + sizeof "LCK.." - 1);
675 #endif
676 #else /* HAVE_SVR4_LOCKFILES */
677       {
678 	struct stat s;
679 
680 	if (*z != '/')
681 	  {
682 	    zalc = (char *) alloca (sizeof "/dev/" + strlen (z));
683 	    sprintf (zalc, "/dev/%s", z);
684 	    z = zalc;
685 	  }
686 	if (stat (z, &s) != 0)
687 	  {
688 	    ulog (LOG_ERROR, "stat (%s): %s", z, strerror (errno));
689 	    return FALSE;
690 	  }
691 	zalc = (char *) alloca (sizeof "LK.123.123.123");
692 	sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev),
693 		 major (s.st_rdev), minor (s.st_rdev));
694       }
695 #endif /* HAVE_SVR4_LOCKFILES */
696 
697       z = zalc;
698     }
699 
700   if (flok)
701     return fsdo_lock (z, FALSE);
702   else
703     return fsdo_unlock (z, FALSE);
704 }
705 
706 /* If we can mark a modem line in use, then when we lock a port we
707    must open it and mark it in use.  We can't wait until the actual
708    open because we can't fail out if it is locked then.  */
709 
710 static boolean
711 fsserial_lock (qport, q, fin, zdevice)
712      const struct sport *qport;
713      struct ssysdep_serial_port *q;
714      boolean fin;
715      const char *zdevice;
716 {
717   if (! fsserial_lockfile (TRUE, qport, zdevice))
718     return FALSE;
719 
720 #if HAVE_TIOCSINUSE || HAVE_TIOCEXCL
721   /* Open the line and, if possible, mark it in use.  */
722   {
723     const char *z;
724     int oread, iflag;
725 
726     z = zdevice;
727     if (z == NULL)
728       {
729 	z = qport->zname;
730 	if (z == NULL)
731 	  return TRUE;
732       }
733 
734     if (fin)
735       iflag = 0;
736     else
737       iflag = FILE_UNBLOCKED;
738 
739     if (*z != '/')
740       {
741 	char *zcopy;
742 
743 	zcopy = (char *) alloca (sizeof "/dev/" + strlen (z));
744 	sprintf (zcopy, "/dev/%s", z);
745 	z = zcopy;
746       }
747 
748     oread = open (z, O_RDWR | iflag);
749     if (oread < 0)
750       {
751 	if (errno != EBUSY)
752 	  ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
753 	(void) fsserial_lockfile (FALSE, qport, zdevice);
754 	return FALSE;
755       }
756 
757 #if HAVE_TIOCSINUSE
758     /* If we can't mark it in use, return FALSE to indicate that the
759        lock failed.  */
760     if (ioctl (oread, TIOCSINUSE, 0) < 0)
761       {
762 	if (errno != EALREADY)
763 	  ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno));
764 	(void) close (oread);
765 	(void) fsserial_lockfile (FALSE, qport, zdevice);
766 	return FALSE;
767       }
768 #endif
769 
770 #ifdef TIOCSCTTY
771     /* On BSD 4.4, make it our controlling terminal.  */
772     (void) ioctl (oread, TIOCSCTTY, 0);
773 #endif
774 
775     q->oread = q->owrite = oread;
776   }
777 #endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
778 
779   return TRUE;
780 }
781 
782 /* We don't need to lock a stdin port.  */
783 
784 /*ARGSUSED*/
785 boolean
786 fsysdep_stdin_lock (qport, fin)
787      struct sport *qport;
788      boolean fin;
789 {
790   return TRUE;
791 }
792 
793 /* Lock a modem port.  */
794 
795 boolean
796 fsysdep_modem_lock (qport, fin)
797      struct sport *qport;
798      boolean fin;
799 {
800   return fsserial_lock (qport, &qport->u.smodem.s.s, fin,
801 			qport->u.smodem.zdevice);
802 }
803 
804 /* Lock a direct port.  */
805 
806 boolean
807 fsysdep_direct_lock (qport, fin)
808      struct sport *qport;
809      boolean fin;
810 {
811   return fsserial_lock (qport, &qport->u.sdirect.s.s, fin,
812 			qport->u.sdirect.zdevice);
813 }
814 
815 /* Open a serial line.  This sets the terminal settings.  We begin in
816    seven bit mode and let the protocol change if necessary.  */
817 
818 static struct sbaud_table
819 {
820 #if HAVE_POSIX_TERMIOS
821   speed_t icode;
822 #else
823   int icode;
824 #endif
825   long ibaud;
826 } asSbaud_table[] =
827 {
828   { B50, 50 },
829   { B75, 75 },
830   { B110, 110 },
831   { B134, 134 },
832   { B150, 150 },
833   { B200, 200 },
834   { B300, 300 },
835   { B600, 600 },
836   { B1200, 1200 },
837   { B1800, 1800 },
838   { B2400, 2400 },
839   { B4800, 4800 },
840   { B9600, 9600 },
841 #ifdef B19200
842   { B19200, 19200 },
843 #else /* ! defined (B19200) */
844 #ifdef EXTA
845   { EXTA, 19200 },
846 #endif /* EXTA */
847 #endif /* ! defined (B19200) */
848 #ifdef B38400
849   { B38400, 38400 }
850 #else /* ! defined (B38400) */
851 #ifdef EXTB
852   { EXTB, 38400 }
853 #endif /* EXTB */
854 #endif /* ! defined (B38400) */
855 };
856 
857 #define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0])
858 
859 #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
860 /* Hold the MIN value for the terminal to avoid setting it
861    unnecessarily.  */
862 static int cSmin;
863 #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
864 
865 static boolean
866 fsserial_open (z, ibaud, fwait, q)
867      const char *z;
868      long ibaud;
869      boolean fwait;
870      struct ssysdep_serial_port *q;
871 {
872 #if HAVE_POSIX_TERMIOS
873   speed_t ib;
874 #else
875   int ib;
876 #endif
877 
878   if (z == NULL)
879     {
880       const char *zport;
881       boolean fdummy;
882 
883       zport = zsysdep_port_name (&fdummy);
884       if (zport != NULL)
885 	ulog_device (zport);
886     }
887   else
888     {
889       if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0)
890 	ulog_device (z + sizeof "/dev/" - 1);
891       else
892 	ulog_device (z);
893     }
894 
895   ib = B0;
896 
897   if (ibaud != 0)
898     {
899       int i;
900 
901       for (i = 0; i < CBAUD_TABLE; i++)
902 	if (asSbaud_table[i].ibaud == ibaud)
903 	  break;
904       if (i >= CBAUD_TABLE)
905 	{
906 	  ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud);
907 	  if (q->oread != -1)
908 	    {
909 	      (void) close (q->oread);
910 	      if (q->oread != q->owrite)
911 		(void) close (q->owrite);
912 	    }
913 	  return FALSE;
914 	}
915       ib = asSbaud_table[i].icode;
916     }
917 
918   /* The port may have already been opened by the locking routine.  */
919   if (q->oread == -1)
920     {
921       int oread, owrite;
922 
923       if (z == NULL)
924 	{
925 	  oread = 0;
926 	  owrite = 1;
927 	}
928       else
929 	{
930 	  int iflag;
931 
932 	  if (fwait)
933 	    iflag = 0;
934 	  else
935 	    iflag = FILE_UNBLOCKED;
936 
937 	  if (*z != '/')
938 	    {
939 	      char *zcopy;
940 
941 	      zcopy = (char *) alloca (sizeof "/dev/" + strlen (z));
942 	      sprintf (zcopy, "/dev/%s", z);
943 	      z = zcopy;
944 	    }
945 
946 	  oread = open (z, O_RDWR | iflag);
947 	  if (oread < 0)
948 	    {
949 	      ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
950 	      return FALSE;
951 	    }
952 
953 #ifdef TIOCSCTTY
954 	  /* On BSD 4.4, make it our controlling terminal.  */
955 	  (void) ioctl (oread, TIOCSCTTY, 0);
956 #endif
957 
958 	  owrite = oread;
959 	}
960 
961       q->oread = oread;
962       q->owrite = owrite;
963     }
964 
965   /* Make sure the ports are blocking.  */
966 
967   if (fcntl (q->oread, F_SETFL, 0) < 0
968       || (q->oread != q->owrite
969 	  && fcntl (q->owrite, F_SETFL, 0) < 0))
970     {
971       ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
972       (void) close (q->oread);
973       if (q->oread != q->owrite)
974 	(void) close (q->owrite);
975       return FALSE;
976     }
977 
978   q->fread_blocking = TRUE;
979 
980   if (! fgetterminfo (q->oread, &q->sorig))
981     {
982       q->fterminal = FALSE;
983       return TRUE;
984     }
985 
986   q->fterminal = TRUE;
987 
988   q->snew = q->sorig;
989 
990 #if HAVE_BSD_TTY
991 
992   q->snew.sg_flags = RAW | ANYP;
993   if (ibaud == 0)
994     ib = q->snew.sg_ospeed;
995   else
996     {
997       q->snew.sg_ispeed = ib;
998       q->snew.sg_ospeed = ib;
999     }
1000 
1001 #ifdef TIOCHPCL
1002   /* When the file is closed, hang up the line.  This is a safety
1003      measure in case the program crashes.  */
1004   (void) ioctl (q->oread, TIOCHPCL, 0);
1005 #endif
1006 
1007 #ifdef TIOCFLUSH
1008   {
1009     int iparam;
1010 
1011     /* Flush pending input.  */
1012 #ifdef FREAD
1013     iparam = FREAD;
1014 #else
1015     iparam = 0;
1016 #endif
1017     (void) ioctl (q->oread, TIOCFLUSH, &iparam);
1018   }
1019 #endif /* TIOCFLUSH */
1020 
1021 #endif /* HAVE_BSD_TTY */
1022 
1023 #if HAVE_SYSV_TERMIO
1024 
1025   if (ibaud == 0)
1026     ib = q->snew.c_cflag & CBAUD;
1027 
1028   q->snew.c_iflag &=~ ICLEAR_IFLAG;
1029   q->snew.c_oflag &=~ ICLEAR_OFLAG;
1030   q->snew.c_cflag &=~ ICLEAR_CFLAG;
1031   q->snew.c_cflag |= (ib | ISET_CFLAG);
1032   q->snew.c_lflag &=~ ICLEAR_LFLAG;
1033   cSmin = 6;
1034   q->snew.c_cc[VMIN] = cSmin;
1035   q->snew.c_cc[VTIME] = 0;
1036 
1037 #ifdef TCFLSH
1038   /* Flush pending input.  */
1039   (void) ioctl (q->oread, TCFLSH, 0);
1040 #endif
1041 
1042 #endif /* HAVE_SYSV_TERMIO */
1043 
1044 #if HAVE_POSIX_TERMIOS
1045 
1046   if (ibaud == 0)
1047     ib = cfgetospeed (&q->snew);
1048 
1049   q->snew.c_iflag &=~ ICLEAR_IFLAG;
1050   q->snew.c_oflag &=~ ICLEAR_OFLAG;
1051   q->snew.c_cflag &=~ ICLEAR_CFLAG;
1052   q->snew.c_cflag |= ISET_CFLAG;
1053   q->snew.c_lflag &=~ ICLEAR_LFLAG;
1054   cSmin = 6;
1055   q->snew.c_cc[VMIN] = cSmin;
1056   q->snew.c_cc[VTIME] = 0;
1057 
1058   (void) cfsetospeed (&q->snew, ib);
1059   (void) cfsetispeed (&q->snew, ib);
1060 
1061   /* Flush pending input.  */
1062   (void) tcflush (q->oread, TCIFLUSH);
1063 
1064 #endif /* HAVE_POSIX_TERMIOS */
1065 
1066   if (! fsetterminfo (q->oread, &q->snew))
1067     {
1068       ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
1069       (void) close (q->oread);
1070       if (q->oread != q->owrite)
1071 	(void) close (q->owrite);
1072       return FALSE;
1073     }
1074 
1075   if (ibaud != 0)
1076     q->ibaud = ibaud;
1077   else
1078     {
1079       int i;
1080 
1081       q->ibaud = 1200;
1082       for (i = 0; i < CBAUD_TABLE; i++)
1083 	{
1084 	  if (asSbaud_table[i].icode == ib)
1085 	    {
1086 	      q->ibaud = asSbaud_table[i].ibaud;
1087 	      break;
1088 	    }
1089 	}
1090 
1091       DEBUG_MESSAGE1 (DEBUG_PORT,
1092 		      "fsserial_open: Baud rate is %ld", q->ibaud);
1093     }
1094 
1095   return TRUE;
1096 }
1097 
1098 /* Open a stdin port.  */
1099 
1100 boolean
1101 fsysdep_stdin_open (qport, ibaud, fwait)
1102      struct sport *qport;
1103      long ibaud;
1104      boolean fwait;
1105 {
1106   return fsserial_open ((const char *) NULL, ibaud, fwait,
1107 			&qport->u.sstdin.s.s);
1108 }
1109 
1110 /* Open a modem port.  */
1111 
1112 boolean
1113 fsysdep_modem_open (qport, ibaud, fwait)
1114      struct sport *qport;
1115      long ibaud;
1116      boolean fwait;
1117 {
1118   const char *z;
1119   boolean fret;
1120 
1121   z = qport->u.smodem.zdevice;
1122   if (z == NULL)
1123     {
1124       z = qport->zname;
1125       if (z == NULL)
1126 	{
1127 	  ulog (LOG_ERROR, "Port has no name or device");
1128 	  return FALSE;
1129 	}
1130     }
1131   if (ibaud == 0)
1132     ibaud = qport->u.smodem.ibaud;
1133   fret = fsserial_open (z, ibaud, fwait, &qport->u.smodem.s.s);
1134   if (! fret)
1135     (void) fsserial_lockfile (FALSE, qport, qport->u.smodem.zdevice);
1136   return fret;
1137 }
1138 
1139 /* Open a direct port.  */
1140 
1141 boolean
1142 fsysdep_direct_open (qport, ibaud, fwait)
1143      struct sport *qport;
1144      long ibaud;
1145      boolean fwait;
1146 {
1147   const char *z;
1148   boolean fret;
1149 
1150   z = qport->u.sdirect.zdevice;
1151   if (z == NULL)
1152     {
1153       z = qport->zname;
1154       if (z == NULL)
1155 	{
1156 	  ulog (LOG_ERROR, "Port has no name or device");
1157 	  return FALSE;
1158 	}
1159     }
1160   if (ibaud == 0)
1161     ibaud = qport->u.sdirect.ibaud;
1162   fret = fsserial_open (z, ibaud, fwait, &qport->u.sdirect.s.s);
1163   if (! fret)
1164     (void) fsserial_lockfile (FALSE, qport, qport->u.sdirect.zdevice);
1165   return fret;
1166 }
1167 
1168 /* Change the blocking status of the port.  We keep track of the
1169    current blocking status to avoid calling fcntl unnecessarily; fcntl
1170    turns out to be surprisingly expensive, at least on Ultrix.  We
1171    used to keep track of the blocking status of the read port and the
1172    write port independently.  Unfortunately, this is nonportable,
1173    because on BSD, and probably some other systems, unblocking a
1174    terminal applies to all descriptors to that terminal.  Now, if
1175    oread != owrite, we set both.  */
1176 
1177 __inline__
1178 static boolean
1179 fsblock (qs, fblock)
1180      struct ssysdep_serial_port *qs;
1181      boolean fblock;
1182 {
1183   if (fblock ? ! qs->fread_blocking : qs->fread_blocking)
1184     {
1185       int iset;
1186 
1187       if (fblock)
1188 	iset = 0;
1189       else
1190 	iset = FILE_UNBLOCKED;
1191       if (fcntl (qs->oread, F_SETFL, iset) < 0
1192 	  || (qs->oread != qs->owrite
1193 	      && fcntl (qs->owrite, F_SETFL, iset) < 0))
1194 	{
1195 	  ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
1196 	  return FALSE;
1197 	}
1198       qs->fread_blocking = fblock;
1199     }
1200   return TRUE;
1201 }
1202 
1203 /* Close a serial port.  */
1204 
1205 static boolean
1206 fsserial_close (q)
1207      struct ssysdep_serial_port *q;
1208 {
1209   if (q->oread >= 0)
1210     {
1211       /* Use a 30 second timeout to avoid hanging while draining
1212 	 output.  */
1213       if (q->fterminal)
1214 	{
1215 	  fSalarm = FALSE;
1216 
1217 	  if (fsysdep_catch ())
1218 	    {
1219 	      usysdep_start_catch ();
1220 	      usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
1221 	      (void) alarm (30);
1222 
1223 	      (void) fsetterminfodrain (q->oread, &q->sorig);
1224 	    }
1225 
1226 	  usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
1227 	  (void) alarm (0);
1228 	  usysdep_end_catch ();
1229 
1230 	  /* If we timed out, use the non draining call.  Hopefully
1231 	     this can't hang.  */
1232 	  if (fSalarm)
1233 	    (void) fsetterminfo (q->oread, &q->sorig);
1234 	}
1235 
1236       (void) close (q->oread);
1237       if (q->oread != q->owrite)
1238 	(void) close (q->owrite);
1239       q->oread = q->owrite = -1;
1240 
1241       /* Sleep for a second to give the terminal a chance to settle,
1242 	 in case we are about to call out again.  */
1243       sleep (1);
1244     }
1245 
1246   return TRUE;
1247 }
1248 
1249 /* Close a stdin port.  */
1250 
1251 /*ARGSUSED*/
1252 boolean
1253 fsysdep_stdin_close (qport, fsuccess)
1254      struct sport *qport;
1255      boolean fsuccess;
1256 {
1257   return fsserial_close (&qport->u.sstdin.s.s);
1258 }
1259 
1260 /* Close a modem port.  */
1261 
1262 boolean
1263 fsysdep_modem_close (qport, fsuccess)
1264      struct sport *qport;
1265      boolean fsuccess;
1266 {
1267   boolean fret;
1268   struct sdialer *qdial;
1269   struct sdialer sdial;
1270 
1271   fret = TRUE;
1272   qdial = NULL;
1273 
1274   /* We're no longer interested in carrier.  */
1275   (void) fsysdep_modem_no_carrier (qport);
1276 
1277   if (qport->u.smodem.zdialer != NULL)
1278     {
1279       char *zcopy;
1280 
1281       zcopy = (char *) alloca (strlen (qport->u.smodem.zdialer) + 1);
1282       strcpy (zcopy, qport->u.smodem.zdialer);
1283       zcopy[strcspn (zcopy, " \t")] = '\0';
1284       if (! fread_dialer_info (zcopy, &sdial))
1285 	fret = FALSE;
1286       else
1287 	qdial = &sdial;
1288     }
1289   else
1290     qdial = qport->u.smodem.qdialer;
1291 
1292   if (qdial != NULL)
1293     {
1294       boolean fsighup_ignored;
1295       HELD_SIG_MASK smask;
1296       int i;
1297       sig_atomic_t afhold[INDEXSIG_COUNT];
1298       const struct schat_info *qchat;
1299 
1300       /* The port I/O routines check whether any signal has been
1301 	 received, and abort if one has.  While we are closing down
1302 	 the modem, we don't care if we received a signal in the past,
1303 	 but we do care if we receive a new signal (otherwise it would
1304 	 be difficult to kill a uucico which was closing down a
1305 	 modem).  We never care if we get SIGHUP at this point.  So we
1306 	 turn off SIGHUP, remember what signals we've already seen,
1307 	 and clear our notion of what signals we've seen.  We have to
1308 	 block the signals while we remember and clear the array,
1309 	 since we might otherwise miss a signal which occurred between
1310 	 the copy and the clear (old systems can't block signals; they
1311 	 will just have to suffer the race).  */
1312 
1313       usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored);
1314       smask = isblocksigs ();
1315       for (i = 0; i < INDEXSIG_COUNT; i++)
1316 	{
1317 	  afhold[i] = afSignal[i];
1318 	  afSignal[i] = FALSE;
1319 	}
1320       usunblocksigs (smask);
1321 
1322       if (fsuccess)
1323 	qchat = &qdial->scomplete;
1324       else
1325 	qchat = &qdial->sabort;
1326       if (! fchat (qchat, (const struct ssysteminfo *) NULL,
1327 		   (const struct sdialer *) NULL, (const char *) NULL,
1328 		   FALSE, qport->zname, qport->u.smodem.s.s.ibaud))
1329 	fret = FALSE;
1330 
1331       /* Restore the old signal array and the SIGHUP handler.  It is
1332 	 not necessary to block signals here, since all we are doing
1333 	 is exactly what the signal handler itself would do if the
1334 	 signal occurred.  */
1335       for (i = 0; i < INDEXSIG_COUNT; i++)
1336 	if (afhold[i])
1337 	  afSignal[i] = TRUE;
1338       if (! fsighup_ignored)
1339 	usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
1340     }
1341 
1342   if (! fsserial_close (&qport->u.smodem.s.s))
1343     fret = FALSE;
1344 
1345   if (! fsserial_lockfile (FALSE, qport, qport->u.smodem.zdevice))
1346     fret = FALSE;
1347 
1348   return fret;
1349 }
1350 
1351 /* Close a direct port.  */
1352 
1353 /*ARGSUSED*/
1354 boolean
1355 fsysdep_direct_close (qport, fsuccess)
1356      struct sport *qport;
1357      boolean fsuccess;
1358 {
1359   boolean fret;
1360 
1361   fret = fsserial_close (&qport->u.sdirect.s.s);
1362 
1363   if (! fsserial_lockfile (FALSE, qport, qport->u.sdirect.zdevice))
1364     fret = FALSE;
1365 
1366   return fret;
1367 }
1368 
1369 /* Reset a serial port by hanging up.  */
1370 
1371 #if ! HAVE_POSIX_TERMIOS
1372 
1373 static boolean
1374 fsserial_reset (q)
1375      struct ssysdep_serial_port *q;
1376 {
1377   sterminal sbaud;
1378 
1379   if (! q->fterminal)
1380     return TRUE;
1381 
1382   sbaud = q->snew;
1383 
1384 #if HAVE_BSD_TTY
1385   sbaud.sg_ispeed = B0;
1386   sbaud.sg_ospeed = B0;
1387 #else /* ! HAVE_BSD_TTY */
1388   sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
1389 #endif /* ! HAVE_BSD_TTY */
1390 
1391   if (! fsetterminfodrain (q->oread, &sbaud))
1392     ulog (LOG_FATAL, "Can't hangup terminal: %s", strerror (errno));
1393 
1394   /* Give the terminal a chance to settle.  */
1395   sleep (1);
1396 
1397   if (! fsetterminfo (q->oread, &q->snew))
1398     ulog (LOG_FATAL, "Can't reopen terminal: %s", strerror (errno));
1399 
1400   return TRUE;
1401 }
1402 
1403 #else /* HAVE_POSIX_TERMIOS */
1404 
1405 static boolean
1406 fsserial_reset (q)
1407      struct ssysdep_serial_port *q;
1408 {
1409   sterminal sbaud;
1410   speed_t iin, iout;
1411 
1412   if (! q->fterminal)
1413     return TRUE;
1414 
1415   iin = cfgetispeed (&q->snew);
1416   iout = cfgetospeed (&q->snew);
1417 
1418   sbaud = q->snew;
1419 
1420   if (cfsetospeed (&sbaud, B0) != 0
1421       || ! fsetterminfodrain (q->oread, &sbaud))
1422     ulog (LOG_FATAL, "Can't hangup terminal: %s", strerror (errno));
1423 
1424   /* Give the terminal a chance to settle.  */
1425   sleep (1);
1426 
1427   if (cfsetispeed (&q->snew, iin) != 0
1428       || cfsetospeed (&q->snew, iout) != 0
1429       || ! fsetterminfo (q->oread, &q->snew))
1430     ulog (LOG_FATAL, "Can't reopen terminal: %s", strerror (errno));
1431 
1432   return TRUE;
1433 }
1434 
1435 #endif /* HAVE_POSIX_TERMIOS */
1436 
1437 /* Reset a stdin port.  */
1438 
1439 boolean
1440 fsysdep_stdin_reset (qport)
1441      struct sport *qport;
1442 {
1443   return fsserial_reset (&qport->u.sstdin.s.s);
1444 }
1445 
1446 /* Reset a modem port.  */
1447 
1448 boolean
1449 fsysdep_modem_reset (qport)
1450      struct sport *qport;
1451 {
1452   return fsserial_reset (&qport->u.smodem.s.s);
1453 }
1454 
1455 /* Reset a direct port.  */
1456 
1457 boolean
1458 fsysdep_direct_reset (qport)
1459      struct sport *qport;
1460 {
1461   return fsserial_reset (&qport->u.sdirect.s.s);
1462 }
1463 
1464 /* Begin dialing out on a modem port.  This opens the dialer device if
1465    there is one.  */
1466 
1467 boolean
1468 fsysdep_modem_begin_dial (qport, qdial)
1469      struct sport *qport;
1470      struct sdialer *qdial;
1471 {
1472 #ifdef TIOCMODEM
1473   /* If we can tell the modem to obey modem control, do so.  */
1474   {
1475     int iperm;
1476 
1477     iperm = 0;
1478     (void) ioctl (qport->u.smodem.s.s.oread, TIOCMODEM, &iperm);
1479   }
1480 #endif /* TIOCMODEM */
1481 
1482 #ifdef TIOCCDTR
1483   /* If we supposed to toggle DTR, do so.  */
1484 
1485   if (qdial->fdtr_toggle)
1486     {
1487       (void) ioctl (qport->u.smodem.s.s.oread, TIOCCDTR, 0);
1488       (void) ioctl (qport->u.smodem.s.s.oread, TIOCSDTR, 0);
1489 
1490       if (qdial->fdtr_toggle_wait)
1491 	sleep (1);
1492     }
1493 #endif /* TIOCCDTR */
1494 
1495   if (! fsysdep_modem_no_carrier (qport))
1496     return FALSE;
1497 
1498   /* Open the dial device if there is one.  */
1499   if (qport->u.smodem.zdial_device != NULL)
1500     {
1501       const char *z;
1502       int oread;
1503 
1504       qport->u.smodem.s.s.oholdread = qport->u.smodem.s.s.oread;
1505       qport->u.smodem.s.s.oholdwrite = qport->u.smodem.s.s.owrite;
1506 
1507       z = qport->u.smodem.zdial_device;
1508       if (*z != '/')
1509 	{
1510 	  char *zcopy;
1511 
1512 	  zcopy = (char *) alloca (sizeof "/dev/" + strlen (z));
1513 	  sprintf (zcopy, "/dev/%s", z);
1514 	  z = zcopy;
1515 	}
1516 
1517       oread = open (z, O_RDWR);
1518       if (oread < 0)
1519 	{
1520 	  ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
1521 	  return FALSE;
1522 	}
1523 
1524       qport->u.smodem.s.s.oread = qport->u.smodem.s.s.owrite = oread;
1525     }
1526 
1527   return TRUE;
1528 }
1529 
1530 /* Tell the port to not require carrier.  I don't know how to do this
1531    on a BSD system that doesn't support TIOCNCAR, if there are any
1532    such systems.  */
1533 
1534 boolean
1535 fsysdep_modem_no_carrier (qport)
1536      struct sport *qport;
1537 {
1538   if (! qport->u.smodem.s.s.fterminal)
1539     return TRUE;
1540 
1541 #ifdef TIOCNCAR
1542   /* Tell the modem to ignore carrier.  */
1543   if (ioctl (qport->u.smodem.s.s.oread, TIOCNCAR, 0) < 0)
1544     {
1545       ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno));
1546       return FALSE;
1547     }
1548 #endif /* TIOCNCAR */
1549 
1550 #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1551   /* Put the modem into local mode (ignore carrier) to start the chat
1552      script.  */
1553   qport->u.smodem.s.s.snew.c_cflag |= CLOCAL;
1554   if (! fsetterminfo (qport->u.smodem.s.s.oread,
1555 		      &qport->u.smodem.s.s.snew))
1556     {
1557       ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno));
1558       return FALSE;
1559     }
1560 #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
1561 
1562   return TRUE;
1563 }
1564 
1565 /* Tell the port to require carrier.  If the port does not support
1566    carrier, we do nothing.  We do not need to worry whether the
1567    dialer supports carrier, since this will only be called when
1568    explicitly requested by a dialer chat script.  */
1569 
1570 boolean
1571 fsysdep_modem_need_carrier (qport)
1572      struct sport *qport;
1573 {
1574   if (! qport->u.smodem.s.s.fterminal)
1575     return TRUE;
1576 
1577   if (qport->u.smodem.fcarrier)
1578     {
1579 #ifdef TIOCCAR
1580       /* Tell the modem to pay attention to carrier.  */
1581       if (ioctl (qport->u.smodem.s.s.oread, TIOCCAR, 0) < 0)
1582 	{
1583 	  ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno));
1584 	  return FALSE;
1585 	}
1586 #endif /* TIOCCAR */
1587 
1588 #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1589       /* Put the modem into nonlocal mode.  */
1590       qport->u.smodem.s.s.snew.c_cflag &=~ CLOCAL;
1591       if (! fsetterminfo (qport->u.smodem.s.s.oread,
1592 			  &qport->u.smodem.s.s.snew))
1593 	{
1594 	  ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno));
1595 	  return FALSE;
1596 	}
1597 #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
1598     }
1599 
1600   return TRUE;
1601 }
1602 
1603 /* Finish dialing out on a modem by closing any dialer device and waiting
1604    for carrier.  */
1605 
1606 boolean
1607 fsysdep_modem_end_dial (qport, qdial)
1608      struct sport *qport;
1609      struct sdialer *qdial;
1610 {
1611   if (qport->u.smodem.zdial_device != NULL)
1612     {
1613       (void) close (qport->u.smodem.s.s.oread);
1614       qport->u.smodem.s.s.oread = qport->u.smodem.s.s.oholdread;
1615       qport->u.smodem.s.s.owrite = qport->u.smodem.s.s.oholdwrite;
1616     }
1617 
1618   if (qport->u.smodem.fcarrier && qdial->fcarrier)
1619     {
1620       /* Tell the port that we need carrier.  */
1621 
1622       if (! fsysdep_modem_need_carrier (qport))
1623 	return FALSE;
1624 
1625 #ifdef TIOCWONLINE
1626 
1627       /* We know how to wait for carrier, so do so.  */
1628 
1629       /* If we already got a signal, just quit now.  */
1630       if (FGOT_QUIT_SIGNAL ())
1631 	return FALSE;
1632 
1633       /* This bit of code handles signals just like fsserial_read
1634 	 does.  See that function for a longer explanation.  */
1635 
1636       /* Use fsysdep_catch to handle a longjmp from the signal
1637 	 handler.  */
1638 
1639       fSalarm = FALSE;
1640 
1641       if (fsysdep_catch ())
1642 	{
1643 	  /* Start catching SIGALRM; normally we ignore it.  */
1644 	  usysdep_start_catch ();
1645 	  usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
1646 	  (void) alarm (qdial->ccarrier_wait);
1647 
1648 	  /* We really don't care if we get an error, since that will
1649 	     probably just mean that TIOCWONLINE isn't supported in
1650 	     which case there's nothing we can do anyhow.  If we get
1651 	     SIGINT we want to keep waiting for carrier, because
1652 	     SIGINT just means don't start any new sessions.  We don't
1653 	     handle SIGINT correctly if we do a longjmp in the signal
1654 	     handler; too bad.  */
1655 	  while (ioctl (qport->u.smodem.s.s.oread, TIOCWONLINE, 0) < 0
1656 		 && errno == EINTR)
1657 	    {
1658 	      /* Log the signal.  */
1659 	      ulog (LOG_ERROR, (const char *) NULL);
1660 	      if (FGOT_QUIT_SIGNAL () || fSalarm)
1661 		break;
1662 	    }
1663 	}
1664 
1665       /* Turn off the pending SIGALRM and ignore SIGALARM again.  */
1666       usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
1667       (void) alarm (0);
1668       usysdep_end_catch ();
1669 
1670       /* If we got a random signal, just return FALSE.  */
1671       if (FGOT_QUIT_SIGNAL ())
1672 	return FALSE;
1673 
1674       /* If we timed out, give an error.  */
1675       if (fSalarm)
1676 	{
1677 	  ulog (LOG_ERROR, "Timed out waiting for carrier");
1678 	  return FALSE;
1679 	}
1680 
1681 #endif /* TIOCWONLINE */
1682     }
1683 
1684   return TRUE;
1685 }
1686 
1687 /* Read data from a serial port, with a timeout.
1688 
1689    This function should return when we have read cmin characters or
1690    the timeout has occurred.  We have to work a bit to get UNIX to do
1691    this efficiently.  The simple implementation schedules a SIGALRM
1692    signal and then calls read; if there is a single character
1693    available, the call to read will return immediately, so there must
1694    be a loop which terminates when the SIGALRM is delivered or the
1695    correct number of characters has been read.  This can be very
1696    inefficient with a fast CPU or a low baud rate (or both!), since
1697    each call to read may return only one or two characters.
1698 
1699    Under POSIX or System V, we can specify a minimum number of
1700    characters to read, so there is no serious trouble.
1701 
1702    Under BSD, we figure out how many characters we have left to read,
1703    how long it will take for them to arrive at the current baud rate,
1704    and sleep that long.
1705 
1706    Doing this with a timeout and avoiding all possible race conditions
1707    get very hairy, though.  Basically, we're going to schedule a
1708    SIGALRM for when the timeout expires.  I don't really want to do a
1709    longjmp in the SIGALRM handler, though, because that may lose data.
1710    Therefore, I have the signal handler set a variable.  However, this
1711    means that there will be a span of time between the time the code
1712    checks the variable and the time it calls the read system call; if
1713    the SIGALRM occurs during that time, the read might hang forever.
1714    To avoid this, the SIGALRM handler not only sets a global variable,
1715    it also schedules another SIGALRM for one second in the future
1716    (POSIX specifies that a signal handler is permitted to safely call
1717    alarm).  To avoid getting a continual sequence of SIGALRM
1718    interrupts, we change the signal handler to ignore SIGALRM when
1719    we're about to exit the function.  This means that every time we
1720    execute fsserial_read we make at least five system calls.  It's the
1721    best I've been able to come up with, though.
1722 
1723    When fsserial_read finishes, there will be no SIGALRM scheduled and
1724    SIGALRM will be ignored.  */
1725 
1726 static boolean
1727 fsserial_read (q, zbuf, pclen, cmin, ctimeout, freport, fpty)
1728      struct ssysdep_serial_port *q;
1729      char *zbuf;
1730      int *pclen;
1731      int cmin;
1732      int ctimeout;
1733      boolean freport;
1734      boolean fpty;
1735 {
1736   CATCH_PROTECT int cwant;
1737   boolean fret;
1738 
1739   cwant = *pclen;
1740   *pclen = 0;
1741 
1742   /* Guard against a bad timeout.  We return TRUE when a timeout
1743      expires.  It is possible to get a negative timeout here because
1744      the calling code does not check user supplied timeouts for
1745      plausibility.  */
1746   if (ctimeout <= 0)
1747     return TRUE;
1748 
1749   /* We want to do a blocking read.  */
1750   if (! fsblock (q, TRUE))
1751     return FALSE;
1752 
1753   fSalarm = FALSE;
1754 
1755   /* We're going to set up an alarm signal to last for the entire
1756      read.  If the read system call cannot be interrupted, the signal
1757      handler will do a longjmp causing fsysdep_catch (a macro) to
1758      return FALSE.  We handle that here.  If read can be interrupted,
1759      fsysdep_catch will be defined to TRUE.  */
1760 
1761   if (fsysdep_catch ())
1762     {
1763       /* Prepare to catch SIGALRM and schedule the signal.  */
1764       usysdep_start_catch ();
1765       usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
1766       alarm (ctimeout);
1767     }
1768   else
1769     {
1770       /* We caught a signal.  We don't actually have to do anything,
1771 	 as all the appropriate checks are made at the start of the
1772 	 following loop.  */
1773     }
1774 
1775   fret = FALSE;
1776 
1777   while (TRUE)
1778     {
1779       int cgot;
1780 
1781 #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
1782       /* If we can tell the terminal not to return until we have a
1783 	 certain number of characters, do so.  */
1784       if (q->fterminal)
1785 	{
1786 	  int csetmin;
1787 
1788 	  /* I'm not that confident about setting MIN to values larger
1789 	     than 127, although up to 255 would probably work.  */
1790 	  if (cmin < 127)
1791 	    csetmin = cmin;
1792 	  else
1793 	    csetmin = 127;
1794 
1795 	  if (csetmin != cSmin)
1796 	    {
1797 	      q->snew.c_cc[VMIN] = csetmin;
1798 	      if (! fsetterminfo (q->oread, &q->snew))
1799 		{
1800 		  int ierr;
1801 
1802 		  /* We turn off the signal before reporting the error
1803 		     to minimize any problems with interrupted system
1804 		     calls.  */
1805 		  ierr = errno;
1806 		  usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
1807 		  alarm (0);
1808 		  usysdep_end_catch ();
1809 		  ulog (LOG_ERROR, "Can't set MIN for terminal: %s",
1810 			strerror (ierr));
1811 		  return FALSE;
1812 		}
1813 	      cSmin = csetmin;
1814 	    }
1815 	}
1816 #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
1817 
1818       /* If we've received a signal, get out now.  */
1819       if (FGOT_QUIT_SIGNAL ())
1820 	break;
1821 
1822       /* If we've already gotten a SIGALRM, get out with whatever
1823 	 we've accumulated.  */
1824 
1825       if (fSalarm)
1826 	{
1827 	  fret = TRUE;
1828 	  break;
1829 	}
1830 
1831       /* Right here is the race condition which we avoid by having the
1832 	 SIGALRM handler schedule another SIGALRM.  */
1833 
1834       cgot = read (q->oread, zbuf, cwant);
1835 
1836       /* If the read returned an error, check for signals.  */
1837       if (cgot < 0)
1838 	{
1839 	  if (errno == EINTR)
1840 	    {
1841 	      /* Log the signal.  */
1842 	      ulog (LOG_ERROR, (const char *) NULL);
1843 	    }
1844 	  if (fSalarm)
1845 	    {
1846 	      fret = TRUE;
1847 	      break;
1848 	    }
1849 	  if (FGOT_QUIT_SIGNAL ())
1850 	    break;
1851 	}
1852 
1853       /* If read returned an error, get out.  We just ignore EINTR
1854 	 here, since it must be from some signal we don't care about.
1855 	 If the read returned 0 then the line must have been hung up
1856 	 (normally we would have received SIGHUP, but we can't count
1857 	 on that).  We turn off the signals before calling ulog to
1858 	 reduce problems with interrupted system calls.  */
1859       if (cgot <= 0)
1860 	{
1861 	  if (cgot < 0 && errno == EINTR)
1862 	    cgot = 0;
1863 	  else
1864 	    {
1865 	      int ierr;
1866 
1867 	      ierr = errno;
1868 
1869 	      usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
1870 	      alarm (0);
1871 	      usysdep_end_catch ();
1872 
1873 	      if (freport)
1874 		{
1875 		  if (cgot == 0)
1876 		    ulog (LOG_ERROR, "Line disconnected");
1877 		  else
1878 		    ulog (LOG_ERROR, "read: %s", strerror (ierr));
1879 		}
1880 
1881 	      return FALSE;
1882 	    }
1883 	}
1884 
1885       cwant -= cgot;
1886       cmin -= cgot;
1887       zbuf += cgot;
1888       *pclen += cgot;
1889 
1890       /* If we have enough data, get out now.  */
1891 
1892       if (cmin <= 0)
1893 	{
1894 	  fret = TRUE;
1895 	  break;
1896 	}
1897 
1898 #if HAVE_BSD_TTY
1899       /* We still want more data, so sleep long enough for the rest of
1900 	 it to arrive.  We don't this for System V or POSIX because
1901 	 setting MIN is good enough (we can't sleep longer than it
1902 	 takes to get MAX_INPUT characters anyhow).
1903 
1904 	 The baud rate is approximately 10 times the number of
1905 	 characters which will arrive in one second, so the number of
1906 	 milliseconds to sleep ==
1907 	 characters * (milliseconds / character) ==
1908 	 characters * (1000 * (seconds / character)) ==
1909 	 characters * (1000 * (1 / (baud / 10))) ==
1910 	 characters * (10000 / baud)
1911 
1912 	 We arbitrarily reduce the sleep amount by 10 milliseconds to
1913 	 attempt to account for the amount of time it takes to set up
1914 	 the sleep.  This is how long it takes to get half a character
1915 	 at 19200 baud.  We then don't bother to sleep for less than
1916 	 10 milliseconds.  We don't sleep if the read was interrupted.
1917 
1918 	 We use select to sleep.  It would be easy to use poll as
1919 	 well, but it's unlikely that any system with BSD ttys would
1920 	 have poll but not select.  Using select avoids hassles with
1921 	 the pending SIGALRM; if it hits the select will be
1922 	 interrupted, and otherwise the select will not affect it.  */
1923 
1924 #if ! HAVE_SELECT
1925  #error This code requires select; feel free to extend it
1926 #endif
1927 
1928       if (q->fterminal && ! fpty && cmin > 1 && cgot > 0)
1929 	{
1930 	  int csleepchars;
1931 	  int isleep;
1932 
1933 	  /* We don't try to read all the way up to MAX_INPUT,
1934 	     since that might drop a character.  */
1935 
1936 	  if (cmin <= MAX_INPUT - 10)
1937 	    csleepchars = cmin;
1938 	  else
1939 	    csleepchars = MAX_INPUT - 10;
1940 
1941 	  isleep = (int) (((long) csleepchars * 10000L) / q->ibaud);
1942 	  isleep -= 10;
1943 
1944 	  if (isleep > 10)
1945 	    {
1946 	      struct timeval s;
1947 
1948 	      s.tv_sec = isleep / 1000;
1949 	      s.tv_usec = (isleep % 1000) * 1000;
1950 
1951 	      /* Some versions of select take a pointer to an int,
1952 		 while some take a pointer to an fd_set.  I just cast
1953 		 the arguments to a generic pointer, and assume that
1954 		 any machine which distinguishes int * from fd_set *
1955 		 (I would be amazed if there are any such machines)
1956 		 have an appropriate prototype somewhere or other.  */
1957 	      (void) select (0, (pointer) NULL, (pointer) NULL,
1958 			     (pointer) NULL, &s);
1959 
1960 	      /* Here either the select finished sleeping or we got a
1961 		 SIGALRM.  If the latter occurred, fSalarm was set to
1962 		 TRUE; it will be checked at the top of the loop.  */
1963 	    }
1964 	}
1965 #endif /* HAVE_BSD_TTY */
1966     }
1967 
1968   /* Turn off the pending SIGALRM and return.  */
1969 
1970   usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
1971   alarm (0);
1972   usysdep_end_catch ();
1973 
1974   return fret;
1975 }
1976 
1977 /* Read from a stdin port.  */
1978 
1979 boolean
1980 fsysdep_stdin_read (qport, zbuf, pclen, cmin, ctimeout, freport)
1981      struct sport *qport;
1982      char *zbuf;
1983      int *pclen;
1984      int cmin;
1985      int ctimeout;
1986      boolean freport;
1987 {
1988   return fsserial_read (&qport->u.sstdin.s.s, zbuf, pclen, cmin, ctimeout,
1989 			freport, qport->u.sstdin.s.fpty);
1990 }
1991 
1992 /* Read from a modem port.  */
1993 
1994 boolean
1995 fsysdep_modem_read (qport, zbuf, pclen, cmin, ctimeout, freport)
1996      struct sport *qport;
1997      char *zbuf;
1998      int *pclen;
1999      int cmin;
2000      int ctimeout;
2001      boolean freport;
2002 {
2003   return fsserial_read (&qport->u.smodem.s.s, zbuf, pclen, cmin, ctimeout,
2004 			freport, FALSE);
2005 }
2006 
2007 /* Read from a direct port.  */
2008 
2009 boolean
2010 fsysdep_direct_read (qport, zbuf, pclen, cmin, ctimeout, freport)
2011      struct sport *qport;
2012      char *zbuf;
2013      int *pclen;
2014      int cmin;
2015      int ctimeout;
2016      boolean freport;
2017 {
2018   return fsserial_read (&qport->u.sdirect.s.s, zbuf, pclen, cmin, ctimeout,
2019 			freport, FALSE);
2020 }
2021 
2022 /* Write data to a serial port.  */
2023 
2024 static boolean
2025 fsserial_write (q, zwrite, cwrite)
2026      struct ssysdep_serial_port *q;
2027      const char *zwrite;
2028      int cwrite;
2029 {
2030   int czero;
2031 
2032   /* We want blocking writes here.  */
2033   if (! fsblock (q, TRUE))
2034     return FALSE;
2035 
2036   czero = 0;
2037 
2038   while (cwrite > 0)
2039     {
2040       int cdid;
2041 
2042       /* If we've received a signal, don't continue.  */
2043       if (FGOT_QUIT_SIGNAL ())
2044 	return FALSE;
2045 
2046       /* Loop until we don't get an interrupt.  */
2047       while ((cdid = write (q->owrite, zwrite, cwrite)) < 0
2048 	     && errno == EINTR)
2049 	{
2050 	  /* Log the signal.  */
2051 	  ulog (LOG_ERROR, (const char *) NULL);
2052 	  if (FGOT_QUIT_SIGNAL ())
2053 	    return FALSE;
2054 	}
2055 
2056       if (cdid < 0)
2057 	{
2058 	  if (errno != EWOULDBLOCK && errno != EAGAIN)
2059 	    {
2060 	      ulog (LOG_ERROR, "write: %s", strerror (errno));
2061 	      return FALSE;
2062 	    }
2063 	  cdid = 0;
2064 	}
2065 
2066       if (cdid == 0)
2067 	{
2068 	  /* On some systems write will return 0 if carrier is lost.
2069 	     If we fail to write anything ten times in a row, we
2070 	     assume that this has happened.  This is hacked in like
2071 	     this because there seems to be no reliable way to tell
2072 	     exactly why the write returned 0.  */
2073 	  ++czero;
2074 	  if (czero >= 10)
2075 	    {
2076 	      ulog (LOG_ERROR, "Line disconnected");
2077 	      return FALSE;
2078 	    }
2079 	}
2080       else
2081 	{
2082 	  czero = 0;
2083 
2084 	  cwrite -= cdid;
2085 	  zwrite += cdid;
2086 	}
2087     }
2088 
2089   return TRUE;
2090 }
2091 
2092 /* Write to a stdin port.  */
2093 
2094 boolean
2095 fsysdep_stdin_write (qport, zwrite, cwrite)
2096      struct sport *qport;
2097      const char *zwrite;
2098      int cwrite;
2099 {
2100   return fsserial_write (&qport->u.sstdin.s.s, zwrite, cwrite);
2101 }
2102 
2103 /* Write to a modem port.  */
2104 
2105 boolean
2106 fsysdep_modem_write (qport, zwrite, cwrite)
2107      struct sport *qport;
2108      const char *zwrite;
2109      int cwrite;
2110 {
2111   return fsserial_write (&qport->u.smodem.s.s, zwrite, cwrite);
2112 }
2113 
2114 /* Write to a direct port.  */
2115 
2116 boolean
2117 fsysdep_direct_write (qport, zwrite, cwrite)
2118      struct sport *qport;
2119      const char *zwrite;
2120      int cwrite;
2121 {
2122   return fsserial_write (&qport->u.sdirect.s.s, zwrite, cwrite);
2123 }
2124 
2125 /* The fsysdep_io routine is supposed to both read and write data
2126    until it has either filled its read buffer or written out all the
2127    data it was given.  This lets us write out large packets without
2128    losing incoming data.  */
2129 
2130 static boolean
2131 fsserial_io (q, zwrite, pcwrite, zread, pcread)
2132      struct ssysdep_serial_port *q;
2133      const char *zwrite;
2134      int *pcwrite;
2135      char *zread;
2136      int *pcread;
2137 {
2138   int cwrite, cread, czero;
2139 
2140   cwrite = *pcwrite;
2141   *pcwrite = 0;
2142   cread = *pcread;
2143   *pcread = 0;
2144 
2145   czero = 0;
2146 
2147   while (TRUE)
2148     {
2149       int cgot, cdo, cdid;
2150 
2151       /* If we've received a signal, don't continue.  */
2152       if (FGOT_QUIT_SIGNAL ())
2153 	return FALSE;
2154 
2155       /* This used to always use nonblocking writes, but it turns out
2156 	 that some systems don't support them on terminals.
2157 
2158 	 The current algorithm is:
2159 	     loop:
2160 	       unblocked read
2161 	       if read buffer full, return
2162 	       if nothing to write, return
2163 	       if HAVE_UNBLOCKED_WRITES
2164 	         write all data
2165 	       else
2166 	         write up to SINGLE_WRITE bytes
2167 	       if all data written, return
2168 	       if no data written
2169 	         blocked write of up to SINGLE_WRITE bytes
2170 
2171 	 This algorithm should work whether the system supports
2172 	 unblocked writes on terminals or not.  If the system supports
2173 	 unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will
2174 	 call write more often than it needs to.  If the system does
2175 	 not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1,
2176 	 then the write may hang so long that incoming data is lost.
2177 	 This is actually possible at high baud rates on any system
2178 	 when a blocking write is done; there is no solution, except
2179 	 hardware handshaking.  */
2180 
2181       /* Do an unblocked read.  */
2182 
2183       if (! fsblock (q, FALSE))
2184 	return FALSE;
2185 
2186       /* Loop until we get something (error or data) other than an
2187 	 acceptable EINTR.  */
2188       while ((cgot = read (q->oread, zread, cread)) < 0
2189 	     && errno == EINTR)
2190 	{
2191 	  /* Log the signal.  */
2192 	  ulog (LOG_ERROR, (const char *) NULL);
2193 	  if (FGOT_QUIT_SIGNAL ())
2194 	    return FALSE;
2195 	}
2196 
2197       if (cgot < 0)
2198 	{
2199 	  if (errno != EAGAIN && errno != EWOULDBLOCK)
2200 	    {
2201 	      ulog (LOG_ERROR, "read: %s", strerror (errno));
2202 	      return FALSE;
2203 	    }
2204 	  cgot = 0;
2205 	}
2206 
2207       cread -= cgot;
2208       zread += cgot;
2209       *pcread += cgot;
2210 
2211       /* If we've filled the read buffer, or we have nothing left to
2212 	 write, return out.  */
2213 
2214       if (cread <= 0 || cwrite <= 0)
2215 	return TRUE;
2216 
2217       /* The port is currently unblocked.  Do a write.  */
2218 
2219       cdo = cwrite;
2220 
2221 #if ! HAVE_UNBLOCKED_WRITES
2222       if (cdo > SINGLE_WRITE)
2223 	cdo = SINGLE_WRITE;
2224 #endif
2225 
2226       /* Loop until we get something besides EINTR.  */
2227       while ((cdid = write (q->owrite, zwrite, cdo)) < 0
2228 	     && errno == EINTR)
2229 	{
2230 	  /* Log the signal.  */
2231 	  ulog (LOG_ERROR, (const char *) NULL);
2232 	  if (FGOT_QUIT_SIGNAL ())
2233 	    return FALSE;
2234 	}
2235 
2236       if (cdid < 0)
2237 	{
2238 	  if (errno != EWOULDBLOCK && errno != EAGAIN)
2239 	    {
2240 	      ulog (LOG_ERROR, "write: %s", strerror (errno));
2241 	      return FALSE;
2242 	    }
2243 	  cdid = 0;
2244 	}
2245 
2246       if (cdid > 0)
2247 	{
2248 	  /* We wrote some data.  If we wrote everything, return out.
2249 	     Otherwise loop around and do another read.  */
2250 	  cwrite -= cdid;
2251 	  zwrite += cdid;
2252 	  *pcwrite += cdid;
2253 
2254 	  if (cwrite <= 0)
2255 	    return TRUE;
2256 
2257 	  czero = 0;
2258 	}
2259       else
2260 	{
2261 	  /* We didn't write any data.  Do a blocking write.  */
2262 
2263 	  if (! fsblock (q, TRUE))
2264 	    return FALSE;
2265 
2266 	  cdo = cwrite;
2267 	  if (cdo > SINGLE_WRITE)
2268 	    cdo = SINGLE_WRITE;
2269 
2270 	  DEBUG_MESSAGE1 (DEBUG_PORT,
2271 			  "fsserial_io: Blocking write of %d", cdo);
2272 
2273 	  /* Loop until we get something besides EINTR.  */
2274 	  while ((cdid = write (q->owrite, zwrite, cdo)) < 0
2275 		 && errno == EINTR)
2276 	    {
2277 	      /* Log the signal.  */
2278 	      ulog (LOG_ERROR, (const char *) NULL);
2279 	      if (FGOT_QUIT_SIGNAL ())
2280 		return FALSE;
2281 	    }
2282 
2283 	  if (cdid < 0)
2284 	    {
2285 	      ulog (LOG_ERROR, "write: %s", strerror (errno));
2286 	      return FALSE;
2287 	    }
2288 
2289 	  if (cdid == 0)
2290 	    {
2291 	      /* On some systems write will return 0 if carrier is
2292 		 lost.  If we fail to write anything ten times in a
2293 		 row, we assume that this has happened.  This is
2294 		 hacked in like this because there seems to be no
2295 		 reliable way to tell exactly why the write returned
2296 		 0.  */
2297 	      ++czero;
2298 	      if (czero >= 10)
2299 		{
2300 		  ulog (LOG_ERROR, "Line disconnected");
2301 		  return FALSE;
2302 		}
2303 	    }
2304 	  else
2305 	    {
2306 	      cwrite -= cdid;
2307 	      zwrite += cdid;
2308 	      *pcwrite += cdid;
2309 	      czero = 0;
2310 	    }
2311 	}
2312     }
2313 }
2314 
2315 /* I/O to a stdin port.  */
2316 
2317 boolean
2318 fsysdep_stdin_io (qport, zwrite, pcwrite, zread, pcread)
2319      struct sport *qport;
2320      const char *zwrite;
2321      int *pcwrite;
2322      char *zread;
2323      int *pcread;
2324 {
2325   return fsserial_io (&qport->u.sstdin.s.s, zwrite, pcwrite, zread, pcread);
2326 }
2327 
2328 /* I/O to a modem port.  */
2329 
2330 boolean
2331 fsysdep_modem_io (qport, zwrite, pcwrite, zread, pcread)
2332      struct sport *qport;
2333      const char *zwrite;
2334      int *pcwrite;
2335      char *zread;
2336      int *pcread;
2337 {
2338   return fsserial_io (&qport->u.smodem.s.s, zwrite, pcwrite, zread, pcread);
2339 }
2340 
2341 /* I/O to a direct port.  */
2342 
2343 boolean
2344 fsysdep_direct_io (qport, zwrite, pcwrite, zread, pcread)
2345      struct sport *qport;
2346      const char *zwrite;
2347      int *pcwrite;
2348      char *zread;
2349      int *pcread;
2350 {
2351   return fsserial_io (&qport->u.sdirect.s.s, zwrite, pcwrite, zread, pcread);
2352 }
2353 
2354 /* Send a break character to a serial port.  */
2355 
2356 static boolean
2357 fsserial_break (q)
2358      struct ssysdep_serial_port *q;
2359 {
2360 #if HAVE_BSD_TTY
2361   ioctl (q->owrite, TIOCSBRK, 0);
2362   sleep (1);
2363   ioctl (q->owrite, TIOCCBRK, 0);
2364   return TRUE;
2365 #endif /* HAVE_BSD_TTY */
2366 #if HAVE_SYSV_TERMIO
2367   ioctl (q->owrite, TCSBRK, 0);
2368   return TRUE;
2369 #endif /* HAVE_SYSV_TERMIO */
2370 #if HAVE_POSIX_TERMIOS
2371   return tcsendbreak (q->owrite, 0) == 0;
2372 #endif /* HAVE_POSIX_TERMIOS */
2373 }
2374 
2375 /* Send a break character to a stdin port.  */
2376 
2377 boolean
2378 fsysdep_stdin_break (qport)
2379      struct sport *qport;
2380 {
2381   return fsserial_break (&qport->u.sstdin.s.s);
2382 }
2383 
2384 /* Send a break character to a modem port.  */
2385 
2386 boolean
2387 fsysdep_modem_break (qport)
2388      struct sport *qport;
2389 {
2390   return fsserial_break (&qport->u.smodem.s.s);
2391 }
2392 
2393 /* Send a break character to a direct port.  */
2394 
2395 boolean
2396 fsysdep_direct_break (qport)
2397      struct sport *qport;
2398 {
2399   return fsserial_break (&qport->u.sdirect.s.s);
2400 }
2401 
2402 /* Change the setting of a serial port.  */
2403 
2404 static boolean
2405 fsserial_set (q, tset)
2406      struct ssysdep_serial_port *q;
2407      enum tportsetting tset;
2408 {
2409   if (! q->fterminal)
2410     return TRUE;
2411 
2412   switch (tset)
2413     {
2414     case PORTSETTING_EIGHT:
2415 #if HAVE_BSD_TTY
2416       if (q->snew.sg_flags == (RAW | ANYP))
2417 	return TRUE;
2418       q->snew.sg_flags = RAW | ANYP;
2419 #endif
2420 #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
2421       if ((q->snew.c_iflag & ICLEAR_IFLAG) == 0)
2422 	return TRUE;
2423       q->snew.c_iflag &=~ ICLEAR_IFLAG;
2424 #endif
2425       if (! fsetterminfodrain (q->oread, &q->snew))
2426 	{
2427 	  ulog (LOG_ERROR, "Can't go to raw mode: %s", strerror (errno));
2428 	  return FALSE;
2429 	}
2430       return TRUE;
2431 
2432     case PORTSETTING_SEVEN:
2433 #if HAVE_BSD_TTY
2434       if (q->snew.sg_flags == (CBREAK | ANYP | TANDEM))
2435 	return TRUE;
2436       q->snew.sg_flags = CBREAK | ANYP | TANDEM;
2437 #endif /* HAVE_BSD_TTY */
2438 #if HAVE_SYSV_TERMIO | HAVE_POSIX_TERMIOS
2439       {
2440 	int iwant;
2441 
2442 #ifdef CRTSCTS
2443 	/* It would be nice to do this is in a more portable fashion,
2444 	   but in any case this is apparently correct for SunOS.  If
2445 	   we are doing hardware flow control, we don't also send
2446 	   start and stop characters; however, we do recognize
2447 	   incoming start and stop characters.  */
2448 	if ((q->snew.c_cflag & CRTSCTS) != 0)
2449 	  iwant = ISTRIP | IXON;
2450 	else
2451 	  iwant = ISTRIP | IXON | IXOFF;
2452 #else /* ! defined (CRTSCTS) */
2453 	iwant = ISTRIP | IXON | IXOFF;
2454 #endif /* ! defined (CRTSCTS) */
2455 
2456 	if ((q->snew.c_iflag & ICLEAR_IFLAG) == iwant)
2457 	  return TRUE;
2458 
2459 	q->snew.c_iflag &=~ ICLEAR_IFLAG;
2460 	q->snew.c_iflag |= iwant;
2461       }
2462 #endif /* HAVE_SYSV_TERMIO | HAVE_POSIX_TERMIOS */
2463 
2464       if (! fsetterminfodrain (q->oread, &q->snew))
2465 	{
2466 	  ulog (LOG_ERROR, "Can't go to seven bit mode: %s",
2467 		strerror (errno));
2468 	  return FALSE;
2469 	}
2470       return TRUE;
2471 
2472     default:
2473 #if DEBUG > 0
2474       ulog (LOG_FATAL, "fsserial_set: Can't happen");
2475 #endif
2476       return FALSE;
2477     }
2478 }
2479 
2480 /* Change settings of a stdin port.  */
2481 
2482 boolean
2483 fsysdep_stdin_set (qport, tset)
2484      struct sport *qport;
2485      enum tportsetting tset;
2486 {
2487   return fsserial_set (&qport->u.sstdin.s.s, tset);
2488 }
2489 
2490 /* Change settings of a modem port.  */
2491 
2492 boolean
2493 fsysdep_modem_set (qport, tset)
2494      struct sport *qport;
2495      enum tportsetting tset;
2496 {
2497   return fsserial_set (&qport->u.smodem.s.s, tset);
2498 }
2499 
2500 /* Change settings of a direct port.  */
2501 
2502 boolean
2503 fsysdep_direct_set (qport, tset)
2504      struct sport *qport;
2505      enum tportsetting tset;
2506 {
2507   return fsserial_set (&qport->u.sdirect.s.s, tset);
2508 }
2509 
2510 /* Run a chat program.  */
2511 
2512 static boolean
2513 fsrun_chat (oread, owrite, zprog)
2514      int oread;
2515      int owrite;
2516      const char *zprog;
2517 {
2518   int cargs;
2519   const char **azargs;
2520   char *zcopy, *zarg;
2521   int aidescs[3];
2522   FILE *e;
2523   pid_t ipid;
2524   char *z;
2525 
2526   /* Get the arguments into an array to pass to isspawn.  */
2527   zcopy = (char *) alloca (strlen (zprog) + 1);
2528   strcpy (zcopy, zprog);
2529   cargs = 0;
2530   for (zarg = strtok (zcopy, " \t");
2531        zarg != NULL;
2532        zarg = strtok ((char *) NULL, " \t"))
2533     ++cargs;
2534 
2535   azargs = (const char **) alloca ((cargs + 1) * sizeof (const char *));
2536 
2537   strcpy (zcopy, zprog);
2538   cargs = 0;
2539   for (zarg = strtok (zcopy, " \t");
2540        zarg != NULL;
2541        zarg = strtok ((char *) NULL, " \t"))
2542     {
2543       azargs[cargs] = zarg;
2544       ++cargs;
2545     }
2546   azargs[cargs] = NULL;
2547 
2548   aidescs[0] = oread;
2549   aidescs[1] = owrite;
2550   aidescs[2] = SPAWN_READ_PIPE;
2551 
2552   /* Pass fkeepuid, fkeepenv and fshell as TRUE.  This puts the
2553      responsibility of maintaing security on the chat program.  */
2554   ipid = isspawn (azargs, aidescs, TRUE, TRUE, (const char *) NULL,
2555 		  FALSE, TRUE, (const char *) NULL,
2556 		  (const char *) NULL, (const char *) NULL);
2557   if (ipid < 0)
2558     {
2559       ulog (LOG_ERROR, "isspawn (%s): %s", azargs[0], strerror (errno));
2560       return FALSE;
2561     }
2562 
2563   e = fdopen (aidescs[2], (char *) "r");
2564   if (e == NULL)
2565     {
2566       ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
2567       (void) close (aidescs[2]);
2568       (void) kill (ipid, SIGKILL);
2569       (void) iswait ((unsigned long) ipid, (const char *) NULL);
2570       return FALSE;
2571     }
2572 
2573   /* The FILE e now is attached to stderr of the program.  Forward
2574      every line the program outputs to the log file.  */
2575   while ((z = zfgets (e, FALSE)) != NULL)
2576     {
2577       int clen;
2578 
2579       clen = strlen (z);
2580       if (z[clen - 1] == '\n')
2581 	z[clen - 1] = '\0';
2582       if (*z != '\0')
2583 	ulog (LOG_NORMAL, "chat: %s", z);
2584       xfree ((pointer) z);
2585     }
2586 
2587   (void) fclose (e);
2588 
2589   return iswait ((unsigned long) ipid, "Chat program") == 0;
2590 }
2591 
2592 /* Run a chat program on a stdin port.  */
2593 
2594 boolean
2595 fsysdep_stdin_chat (qport, zprog)
2596      struct sport *qport;
2597      const char *zprog;
2598 {
2599   return fsrun_chat (qport->u.sstdin.s.s.oread,
2600 		     qport->u.sstdin.s.s.owrite,
2601 		     zprog);
2602 }
2603 
2604 /* Run a chat program on a modem port.  */
2605 
2606 boolean
2607 fsysdep_modem_chat (qport, zprog)
2608      struct sport *qport;
2609      const char *zprog;
2610 {
2611   return fsrun_chat (qport->u.smodem.s.s.oread,
2612 		     qport->u.smodem.s.s.owrite,
2613 		     zprog);
2614 }
2615 
2616 /* Run a chat program on a direct port.  */
2617 
2618 boolean
2619 fsysdep_direct_chat (qport, zprog)
2620      struct sport *qport;
2621      const char *zprog;
2622 {
2623   return fsrun_chat (qport->u.sdirect.s.s.oread,
2624 		     qport->u.sdirect.s.s.owrite,
2625 		     zprog);
2626 }
2627 
2628 #if HAVE_TCP
2629 
2630 /* Run a chat program on a TCP port.  */
2631 
2632 boolean
2633 fsysdep_tcp_chat (qport, zprog)
2634      struct sport *qport;
2635      const char *zprog;
2636 {
2637   return fsrun_chat (qport->u.stcp.o, qport->u.stcp.o, zprog);
2638 }
2639 
2640 #endif /* HAVE_TCP */
2641 
2642 /* Functions to return baud rates.  */
2643 
2644 /* Return baud rate of a stdin port.  */
2645 
2646 long
2647 isysdep_stdin_baud (qport)
2648      struct sport *qport;
2649 {
2650   return qport->u.sstdin.s.s.ibaud;
2651 }
2652 
2653 /* Return baud rate of a modem port.  */
2654 
2655 long
2656 isysdep_modem_baud (qport)
2657      struct sport *qport;
2658 {
2659   return qport->u.smodem.s.s.ibaud;
2660 }
2661 
2662 /* Return baud rate of a direct port.  */
2663 
2664 long
2665 isysdep_direct_baud (qport)
2666      struct sport *qport;
2667 {
2668   return qport->u.sdirect.s.s.ibaud;
2669 }
2670 
2671 #if HAVE_TCP
2672 
2673 /* Some system dependent routines for TCP ports.  These work by
2674    setting up an ssysdep_serial_port structure to fake out the serial
2675    port routines.  I'm doing it this way to avoid having to write the
2676    complicated timeout code twice, and because the serial port code
2677    will work fine.  It does mean that if the serial port code changes
2678    this code will have to be considered.  */
2679 
2680 /* Read data from a TCP port.  */
2681 
2682 boolean
2683 fsysdep_tcp_read (qport, zread, pclen, cmin, ctimeout, freport)
2684      struct sport *qport;
2685      char *zread;
2686      int *pclen;
2687      int cmin;
2688      int ctimeout;
2689      boolean freport;
2690 {
2691   struct ssysdep_serial_port s;
2692 
2693   s.oread = s.owrite = qport->u.stcp.o;
2694   s.fread_blocking = TRUE;
2695   s.fterminal = FALSE;
2696   return fsserial_read (&s, zread, pclen, cmin, ctimeout, freport, FALSE);
2697 }
2698 
2699 /* Write data to a TCP port.  */
2700 
2701 boolean
2702 fsysdep_tcp_write (qport, zwrite, cwrite)
2703      struct sport *qport;
2704      const char *zwrite;
2705      int cwrite;
2706 {
2707   struct ssysdep_serial_port s;
2708 
2709   s.oread = s.owrite = qport->u.stcp.o;
2710   s.fread_blocking = TRUE;
2711   s.fterminal = FALSE;
2712   return fsserial_write (&s, zwrite, cwrite);
2713 }
2714 
2715 /* Read and write data to and from a TCP port.  We actually don't
2716    bother to really implement this, since the system will buffer up
2717    plenty of TCP data (only 256 bytes are buffered for a terminal,
2718    so losing data becomes a real possibility).  */
2719 
2720 boolean
2721 fsysdep_tcp_io (qport, zwrite, pcwrite, zread, pcread)
2722      struct sport *qport;
2723      const char *zwrite;
2724      int *pcwrite;
2725      char *zread;
2726      int *pcread;
2727 {
2728   struct ssysdep_serial_port s;
2729 
2730   s.oread = s.owrite = qport->u.stcp.o;
2731   s.fread_blocking = TRUE;
2732   s.fterminal = FALSE;
2733   *pcread = 0;
2734   return fsserial_write (&s, zwrite, *pcwrite);
2735 }
2736 
2737 #endif /* HAVE_TCP */
2738 
2739 /*
2740   Local variables:
2741   mode:c
2742   End:
2743   */
2744