1570 lines
34 KiB
C
1570 lines
34 KiB
C
/* tstuu.c
|
||
Test the uucp package on a UNIX system.
|
||
|
||
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: tstuu.c,v $
|
||
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
|
||
initial import of 386bsd-0.1 sources
|
||
|
||
* Revision 1.2 1992/05/13 05:42:07 rich
|
||
* ported to 386bsd
|
||
*
|
||
* Revision 1.1 1992/05/10 20:03:07 rich
|
||
* Initial revision
|
||
*
|
||
Revision 1.52 1992/04/02 23:02:40 ian
|
||
Conditionally declare times
|
||
|
||
Revision 1.51 1992/03/28 04:29:19 ian
|
||
Roberto Biancardi: define SIGCHLD as SIGCLD if necessary
|
||
|
||
Revision 1.50 1992/03/16 22:22:35 ian
|
||
Adjusted external declarations
|
||
|
||
Revision 1.49 1992/03/15 01:54:46 ian
|
||
All execs are now done in isspawn, all waits are done in iswait
|
||
|
||
Revision 1.48 1992/03/12 19:54:43 ian
|
||
Debugging based on types rather than number
|
||
|
||
Revision 1.47 1992/03/08 17:02:24 ian
|
||
Ted Lindgreen: don't include <sys/ioctl.h> if it's not there
|
||
|
||
Revision 1.46 1992/03/04 15:38:19 ian
|
||
Roberto Biancardi: use poll if we haven't got select
|
||
|
||
Revision 1.45 1992/03/04 01:40:51 ian
|
||
Thomas Fischer: tweaked a bit for the NeXT
|
||
|
||
Revision 1.44 1992/02/27 05:40:54 ian
|
||
T. William Wells: detach from controlling terminal, handle signals safely
|
||
|
||
Revision 1.43 1992/02/24 20:07:43 ian
|
||
John Theus: some systems don't have <fcntl.h>
|
||
|
||
Revision 1.42 1992/02/24 04:58:47 ian
|
||
Only permit files to be received into directories that are world-writeable
|
||
|
||
Revision 1.41 1992/02/23 03:26:51 ian
|
||
Overhaul to use automatic configure shell script
|
||
|
||
Revision 1.40 1992/02/08 03:54:18 ian
|
||
Include <string.h> only in <uucp.h>, added 1992 copyright
|
||
|
||
Revision 1.39 1992/01/29 04:27:11 ian
|
||
Jay Vassos-Libove: removed some conflicting declarations
|
||
|
||
Revision 1.38 1992/01/19 02:53:05 ian
|
||
Mike Park: don't sleep when buffer is full; it's too slow
|
||
|
||
Revision 1.37 1992/01/16 16:32:44 ian
|
||
Mike Park: ioctl is sometimes declared varadic, so we can't declare it
|
||
|
||
Revision 1.36 1992/01/15 21:06:11 ian
|
||
Mike Park: some systems can't include <sys/time.h> and <time.h> together
|
||
|
||
Revision 1.35 1992/01/15 20:48:41 ian
|
||
Mike Park: removed prototype for times
|
||
|
||
Revision 1.34 1992/01/15 20:02:05 ian
|
||
Mike Park: sh on NeXT interprets leading ~ (incredible, isn't it)
|
||
|
||
Revision 1.33 1992/01/15 19:40:35 ian
|
||
Mike Park: handle HAVE_UNION_WAIT correctly and completely
|
||
|
||
Revision 1.32 1992/01/13 19:38:16 ian
|
||
Chip Salzenberg: can't declare execl, since it is varadic
|
||
|
||
Revision 1.31 1992/01/13 06:11:39 ian
|
||
David Nugent: can't declare open or fcntl
|
||
|
||
Revision 1.30 1992/01/13 05:53:04 ian
|
||
Mike Park: added HAVE_WAITPID and HAVE_WAIT4 configuration parameters
|
||
|
||
Revision 1.29 1992/01/13 05:37:20 ian
|
||
Mike Park: use IPUBLIC_DIRECTORY_MODE rather than S_ macros
|
||
|
||
Revision 1.28 1991/12/29 04:04:18 ian
|
||
Added a bunch of extern definitions
|
||
|
||
Revision 1.27 1991/12/29 00:55:23 ian
|
||
Monty Solomon: added HAVE_UNION_WAIT
|
||
|
||
Revision 1.26 1991/12/28 06:35:05 ian
|
||
Use TIMES_TICK rather than CLK_TCK
|
||
|
||
Revision 1.25 1991/12/28 06:10:50 ian
|
||
Added HAVE_STRCHR and HAVE_INDEX to conf.h
|
||
|
||
Revision 1.24 1991/12/28 04:05:13 ian
|
||
Create spool directories
|
||
|
||
Revision 1.23 1991/12/28 03:49:23 ian
|
||
Added HAVE_MEMFNS and HAVE_BFNS; changed uses of memset to bzero
|
||
|
||
Revision 1.22 1991/12/22 22:14:19 ian
|
||
Monty Solomon: added HAVE_UNISTD_H configuration parameter
|
||
|
||
Revision 1.21 1991/12/21 22:07:47 ian
|
||
John Theus: don't warn if port file does not exist
|
||
|
||
Revision 1.20 1991/12/19 04:25:57 ian
|
||
Terry Gardner: configuration parameter to not use both NONBLOCK and NDELAY
|
||
|
||
Revision 1.19 1991/12/19 03:55:40 ian
|
||
Give the uucico processes a chance to die on their own
|
||
|
||
Revision 1.18 1991/12/18 05:12:00 ian
|
||
Added -l option to uucico to prompt for login name once and then exit
|
||
|
||
Revision 1.17 1991/12/17 22:21:19 ian
|
||
Sleep before printing login to wait until input has been flushed
|
||
|
||
Revision 1.16 1991/12/17 04:55:01 ian
|
||
David Nugent: ignore SIGHUP in uucico and uuxqt
|
||
|
||
Revision 1.15 1991/12/11 04:21:37 ian
|
||
Arne Ludwig: merge in Arne Ludwig's patches for V2 and BNU style logging
|
||
|
||
Revision 1.14 1991/12/07 02:57:28 ian
|
||
Allow failure message to be sent from uux test
|
||
|
||
Revision 1.13 1991/12/01 19:58:01 ian
|
||
Don't use the not-very-portable fd_set typedef at all
|
||
|
||
Revision 1.12 1991/12/01 19:41:00 ian
|
||
Don't read V2 or BNU configuration files while testing
|
||
|
||
Revision 1.11 1991/12/01 03:29:30 ian
|
||
Bob Izenberg: get definitions for EAGAIN and EWOULDBLOCK
|
||
|
||
Revision 1.10 1991/12/01 02:23:12 ian
|
||
Niels Baggesen: don't multiply include <unistd.h>
|
||
|
||
Revision 1.9 1991/12/01 02:12:02 ian
|
||
David Nugent: some systems don't define O_NDELAY
|
||
|
||
Revision 1.8 1991/11/26 02:13:48 ian
|
||
Bob Denny: Add definitions for FD_SET, FD_ZERO and FD_ISSET
|
||
|
||
Revision 1.7 1991/11/26 01:45:42 ian
|
||
Marty Shannon: configuration option to not include <sys/wait.h>
|
||
|
||
Revision 1.6 1991/11/21 22:17:06 ian
|
||
Add version string, print version when printing usage
|
||
|
||
Revision 1.5 1991/11/14 21:07:15 ian
|
||
Create port file and add protocol command for second system
|
||
|
||
Revision 1.4 1991/11/12 19:47:04 ian
|
||
Add called-chat set of commands to run a chat script on an incoming call
|
||
|
||
Revision 1.3 1991/11/11 23:47:24 ian
|
||
Added chat-program to run a program to do a chat script
|
||
|
||
Revision 1.2 1991/11/11 04:21:16 ian
|
||
Added 'f' protocol
|
||
|
||
Revision 1.1 1991/09/10 19:40:31 ian
|
||
Initial revision
|
||
|
||
*/
|
||
|
||
#include "uucp.h"
|
||
|
||
#if USE_RCS_ID
|
||
char tstuu_rcsid[] = "$Id: tstuu.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
|
||
#endif
|
||
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
#include <errno.h>
|
||
|
||
#if USE_STDIO && HAVE_UNISTD_H
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
#include "sysdep.h"
|
||
|
||
#include <sys/times.h>
|
||
|
||
#if HAVE_SYS_IOCTL_H
|
||
#include <sys/ioctl.h>
|
||
#endif
|
||
|
||
#if HAVE_SELECT
|
||
#include <sys/time.h>
|
||
#endif
|
||
|
||
#if HAVE_POLL
|
||
#include <stropts.h>
|
||
#include <poll.h>
|
||
#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_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_SELECT)
|
||
#include <time.h>
|
||
#endif
|
||
|
||
#if HAVE_SYS_WAIT_H
|
||
#include <sys/wait.h>
|
||
#endif
|
||
|
||
#if HAVE_UNION_WAIT
|
||
typedef union wait wait_status;
|
||
#else
|
||
typedef int wait_status;
|
||
#endif
|
||
|
||
#include "getopt.h"
|
||
|
||
/* 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 CLK_TCK definition, even if it makes no sense.
|
||
This is in case TIMES_TICK is defined as CLK_TCK. */
|
||
#ifndef CLK_TCK
|
||
#define CLK_TCK (60)
|
||
#endif
|
||
|
||
/* Don't try too hard to get a TIMES_TICK value; it doesn't matter
|
||
that much. */
|
||
#if TIMES_TICK == 0
|
||
#undef TIMES_TICK
|
||
#define TIMES_TICK CLK_TCK
|
||
#endif
|
||
|
||
#if TIMES_DECLARATION_OK
|
||
extern long times ();
|
||
#endif
|
||
|
||
#ifndef SIGCHLD
|
||
#define SIGCHLD SIGCLD
|
||
#endif
|
||
|
||
#define ZUUCICO_CMD "login uucp"
|
||
#define UUCICO_EXECL "/bin/login", "login", "uucp"
|
||
|
||
#if ! HAVE_SELECT && ! HAVE_POLL
|
||
#error You need select or poll
|
||
#endif
|
||
|
||
/* External functions. */
|
||
extern int close (), dup2 (), access ();
|
||
extern int read (), write (), unlink ();
|
||
extern int fclose (), fflush (), rand (), system ();
|
||
extern pid_t fork ();
|
||
|
||
#if HAVE_SELECT
|
||
extern int select ();
|
||
#endif
|
||
|
||
#if HAVE_POLL
|
||
extern int poll ();
|
||
#endif
|
||
|
||
#if ! HAVE_WAITPID && HAVE_WAIT4
|
||
extern pid_t wait4 ();
|
||
#endif
|
||
|
||
#if ! HAVE_REMOVE
|
||
#undef remove
|
||
#define remove unlink
|
||
#endif
|
||
|
||
/* Local functions. */
|
||
|
||
static void umake_file P((const char *zfile, int cextra));
|
||
static void uprepare_test P((int itest, boolean fcall_uucico,
|
||
const char *zsys));
|
||
static void ucheck_file P((const char *zfile, const char *zerr,
|
||
int cextra));
|
||
static void ucheck_test P((int itest, boolean fcall_uucico));
|
||
static void utransfer P((int ofrom, int oto, int otoslave, int *pc));
|
||
static SIGtype uchild P((int isig));
|
||
static int cpshow P((char *z, int bchar));
|
||
static void uchoose P((int *po1, int *po2));
|
||
static boolean fwritable P((int o));
|
||
static void xsystem P((const char *zcmd));
|
||
|
||
static char *zDebug;
|
||
static int iTest;
|
||
static boolean fCall_uucico;
|
||
static int iPercent;
|
||
static pid_t iPid1, iPid2;
|
||
static int cFrom1, cFrom2;
|
||
static char abLogout1[sizeof "tstout /dev/ptyp0"];
|
||
static char abLogout2[sizeof "tstout /dev/ptyp0"];
|
||
static char *zProtocols;
|
||
|
||
int
|
||
main (argc, argv)
|
||
int argc;
|
||
char **argv;
|
||
{
|
||
int iopt;
|
||
const char *zcmd1, *zcmd2;
|
||
const char *zpty;
|
||
const char *zsys;
|
||
char abpty1[sizeof "/dev/ptyp0"];
|
||
char abpty2[sizeof "/dev/ptyp0"];
|
||
char *zptyname;
|
||
int omaster1, oslave1, omaster2, oslave2;
|
||
|
||
zcmd1 = NULL;
|
||
zcmd2 = NULL;
|
||
zsys = "test2";
|
||
|
||
while ((iopt = getopt (argc, argv, "c:p:s:t:ux:1:2:")) != EOF)
|
||
{
|
||
switch (iopt)
|
||
{
|
||
case 'c':
|
||
zProtocols = optarg;
|
||
break;
|
||
case 'p':
|
||
iPercent = atoi (optarg);
|
||
break;
|
||
case 's':
|
||
zsys = optarg;
|
||
break;
|
||
case 't':
|
||
iTest = atoi (optarg);
|
||
break;
|
||
case 'u':
|
||
fCall_uucico = TRUE;
|
||
break;
|
||
case 'x':
|
||
zDebug = optarg;
|
||
break;
|
||
case '1':
|
||
zcmd1 = optarg;
|
||
break;
|
||
case '2':
|
||
zcmd2 = optarg;
|
||
break;
|
||
default:
|
||
fprintf (stderr,
|
||
"Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
|
||
abVersion);
|
||
fprintf (stderr,
|
||
"Usage: tstuu [-x] [-t #] [-u] [-1 cmd] [-2 cmd]\n");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
}
|
||
|
||
if (fCall_uucico && zcmd2 == NULL)
|
||
zcmd2 = ZUUCICO_CMD;
|
||
|
||
uprepare_test (iTest, fCall_uucico, zsys);
|
||
|
||
(void) remove ("/usr/tmp/tstuu/spool1/core");
|
||
(void) remove ("/usr/tmp/tstuu/spool2/core");
|
||
|
||
omaster1 = -1;
|
||
oslave1 = -1;
|
||
omaster2 = -1;
|
||
oslave2 = -1;
|
||
zptyname = abpty1;
|
||
|
||
for (zpty = "pqrs"; *zpty != '\0'; ++zpty)
|
||
{
|
||
int ipty;
|
||
|
||
for (ipty = 0; ipty < 16; ipty++)
|
||
{
|
||
int om, os;
|
||
FILE *e;
|
||
|
||
sprintf (zptyname, "/dev/pty%c%c", *zpty,
|
||
"0123456789abcdef"[ipty]);
|
||
om = open (zptyname, O_RDWR);
|
||
if (om < 0)
|
||
continue;
|
||
zptyname[5] = 't';
|
||
os = open (zptyname, O_RDWR);
|
||
if (os < 0)
|
||
{
|
||
(void) close (om);
|
||
continue;
|
||
}
|
||
|
||
if (omaster1 == -1)
|
||
{
|
||
omaster1 = om;
|
||
oslave1 = os;
|
||
|
||
e = fopen ("/usr/tmp/tstuu/pty1", "w");
|
||
if (e == NULL)
|
||
{
|
||
perror ("fopen");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
fprintf (e, "%s", zptyname + 5);
|
||
if (fclose (e) != 0)
|
||
{
|
||
perror ("fclose");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
zptyname = abpty2;
|
||
}
|
||
else
|
||
{
|
||
omaster2 = om;
|
||
oslave2 = os;
|
||
|
||
e = fopen ("/usr/tmp/tstuu/pty2", "w");
|
||
if (e == NULL)
|
||
{
|
||
perror ("fopen");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
fprintf (e, "%s", zptyname + 5);
|
||
if (fclose (e) != 0)
|
||
{
|
||
perror ("fclose");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (omaster1 != -1 && omaster2 != -1)
|
||
break;
|
||
}
|
||
|
||
if (omaster2 == -1)
|
||
{
|
||
fprintf (stderr, "No pseudo-terminals available\n");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
/* Make sure we can or these into an int for the select call. Most
|
||
systems could use 31 instead of 15, but it should never be a
|
||
problem. */
|
||
if (omaster1 > 15 || omaster2 > 15)
|
||
{
|
||
fprintf (stderr, "File descriptors are too large\n");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
/* Prepare to log out the command if it is a login command. On
|
||
Ultrix 4.0 uucico can only be run from login for some reason. */
|
||
|
||
if (zcmd1 == NULL
|
||
|| strncmp (zcmd1, "login", sizeof "login" - 1) != 0)
|
||
abLogout1[0] = '\0';
|
||
else
|
||
sprintf (abLogout1, "tstout %s", abpty1);
|
||
|
||
if (zcmd2 == NULL
|
||
|| strncmp (zcmd2, "login", sizeof "login" - 1) != 0)
|
||
abLogout2[0] = '\0';
|
||
else
|
||
sprintf (abLogout2, "tstout %s", abpty2);
|
||
|
||
iPid1 = fork ();
|
||
if (iPid1 < 0)
|
||
{
|
||
perror ("fork");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
else if (iPid1 == 0)
|
||
{
|
||
if (close (0) < 0
|
||
|| close (1) < 0
|
||
|| close (omaster1) < 0
|
||
|| close (omaster2) < 0
|
||
|| close (oslave2) < 0)
|
||
perror ("close");
|
||
|
||
if (dup2 (oslave1, 0) < 0
|
||
|| dup2 (oslave1, 1) < 0)
|
||
perror ("dup2");
|
||
|
||
if (close (oslave1) < 0)
|
||
perror ("close");
|
||
|
||
if (zDebug != NULL)
|
||
fprintf (stderr, "About to exec first process\n");
|
||
|
||
if (zcmd1 != NULL)
|
||
exit (system ((char *) zcmd1));
|
||
else
|
||
{
|
||
(void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config1",
|
||
"-q", "-S", zsys, "-pstdin", (const char *) NULL);
|
||
fprintf (stderr, "execl failed\n");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
}
|
||
|
||
iPid2 = fork ();
|
||
if (iPid2 < 0)
|
||
{
|
||
perror ("fork");
|
||
kill (iPid1, SIGTERM);
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
else if (iPid2 == 0)
|
||
{
|
||
if (close (0) < 0
|
||
|| close (1) < 0
|
||
|| close (omaster1) < 0
|
||
|| close (oslave1) < 0
|
||
|| close (omaster2) < 0)
|
||
perror ("close");
|
||
|
||
if (dup2 (oslave2, 0) < 0
|
||
|| dup2 (oslave2, 1) < 0)
|
||
perror ("dup2");
|
||
|
||
if (close (oslave2) < 0)
|
||
perror ("close");
|
||
|
||
if (zDebug != NULL)
|
||
fprintf (stderr, "About to exec second process\n");
|
||
|
||
if (fCall_uucico)
|
||
{
|
||
(void) execl (UUCICO_EXECL, (const char *) NULL);
|
||
fprintf (stderr, "execl failed\n");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
else if (zcmd2 != NULL)
|
||
exit (system ((char *) zcmd2));
|
||
else
|
||
{
|
||
(void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config2",
|
||
"-lq", (const char *)NULL);
|
||
fprintf (stderr, "execl failed\n");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
}
|
||
|
||
signal (SIGCHLD, uchild);
|
||
|
||
(void) fcntl (omaster1, F_SETFL, FILE_UNBLOCKED);
|
||
(void) fcntl (omaster2, F_SETFL, FILE_UNBLOCKED);
|
||
|
||
while (TRUE)
|
||
{
|
||
int o1, o2;
|
||
|
||
o1 = omaster1;
|
||
o2 = omaster2;
|
||
uchoose (&o1, &o2);
|
||
|
||
if (o1 == -1 && o2 == -1)
|
||
{
|
||
if (zDebug != NULL)
|
||
fprintf (stderr, "Five second pause\n");
|
||
continue;
|
||
}
|
||
|
||
if (o1 != -1
|
||
&& fwritable (omaster2))
|
||
utransfer (omaster1, omaster2, oslave2, &cFrom1);
|
||
|
||
if (o2 != - 1
|
||
&& fwritable (omaster1))
|
||
utransfer (omaster2, omaster1, oslave1, &cFrom2);
|
||
}
|
||
|
||
/*NOTREACHED*/
|
||
}
|
||
|
||
/* When a child dies, kill them both. */
|
||
|
||
static SIGtype
|
||
uchild (isig)
|
||
int isig;
|
||
{
|
||
struct tms sbase, s1, s2;
|
||
|
||
signal (SIGCHLD, SIG_DFL);
|
||
|
||
/* Give the processes a chance to die on their own. */
|
||
sleep (1);
|
||
|
||
(void) kill (iPid1, SIGTERM);
|
||
(void) kill (iPid2, SIGTERM);
|
||
|
||
(void) times (&sbase);
|
||
|
||
#if HAVE_WAITPID
|
||
(void) waitpid (iPid1, (wait_status *) NULL, 0);
|
||
#else /* ! HAVE_WAITPID */
|
||
#if HAVE_WAIT4
|
||
(void) wait4 (iPid1, (wait_status *) NULL, 0, (struct rusage *) NULL);
|
||
#else /* ! HAVE_WAIT4 */
|
||
(void) wait ((wait_status *) NULL);
|
||
#endif /* ! HAVE_WAIT4 */
|
||
#endif /* ! HAVE_WAITPID */
|
||
|
||
(void) times (&s1);
|
||
|
||
#if HAVE_WAITPID
|
||
(void) waitpid (iPid2, (wait_status *) NULL, 0);
|
||
#else /* ! HAVE_WAITPID */
|
||
#if HAVE_WAIT4
|
||
(void) wait4 (iPid2, (wait_status *) NULL, 0, (struct rusage *) NULL);
|
||
#else /* ! HAVE_WAIT4 */
|
||
(void) wait ((wait_status *) NULL);
|
||
#endif /* ! HAVE_WAIT4 */
|
||
#endif /* ! HAVE_WAITPID */
|
||
|
||
(void) times (&s2);
|
||
|
||
fprintf (stderr,
|
||
" First child: user: %g; system: %g\n",
|
||
(double) (s1.tms_cutime - sbase.tms_cutime) / (double) TIMES_TICK,
|
||
(double) (s1.tms_cstime - sbase.tms_cstime) / (double) TIMES_TICK);
|
||
fprintf (stderr,
|
||
"Second child: user: %g; system: %g\n",
|
||
(double) (s2.tms_cutime - s1.tms_cutime) / (double) TIMES_TICK,
|
||
(double) (s2.tms_cstime - s1.tms_cstime) / (double) TIMES_TICK);
|
||
|
||
ucheck_test (iTest, fCall_uucico);
|
||
|
||
if (abLogout1[0] != '\0')
|
||
{
|
||
if (zDebug != NULL)
|
||
fprintf (stderr, "Executing %s\n", abLogout1);
|
||
(void) system (abLogout1);
|
||
}
|
||
if (abLogout2[0] != '\0')
|
||
{
|
||
if (zDebug != NULL)
|
||
fprintf (stderr, "Executing %s\n", abLogout2);
|
||
(void) system (abLogout2);
|
||
}
|
||
|
||
fprintf (stderr, "Wrote %d bytes from 1 to 2\n", cFrom1);
|
||
fprintf (stderr, "Wrote %d bytes from 2 to 1\n", cFrom2);
|
||
|
||
if (access ("/usr/tmp/tstuu/spool1/core", R_OK) == 0)
|
||
fprintf (stderr, "core file 1 exists\n");
|
||
if (access ("/usr/tmp/tstuu/spool2/core", R_OK) == 0)
|
||
fprintf (stderr, "core file 2 exists\n");
|
||
|
||
exit (EXIT_SUCCESS);
|
||
}
|
||
|
||
/* Open a file without error. */
|
||
|
||
static FILE *xfopen P((const char *zname, const char *zmode));
|
||
|
||
static FILE *
|
||
xfopen (zname, zmode)
|
||
const char *zname;
|
||
const char *zmode;
|
||
{
|
||
FILE *eret;
|
||
|
||
eret = fopen (zname, zmode);
|
||
if (eret == NULL)
|
||
{
|
||
perror (zname);
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
return eret;
|
||
}
|
||
|
||
/* Close a file without error. */
|
||
|
||
static void xfclose P((FILE *e));
|
||
|
||
static void
|
||
xfclose (e)
|
||
FILE *e;
|
||
{
|
||
if (fclose (e) != 0)
|
||
{
|
||
perror ("fclose");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
}
|
||
|
||
/* Create a test file. */
|
||
|
||
static void
|
||
umake_file (z, c)
|
||
const char *z;
|
||
int c;
|
||
{
|
||
int i;
|
||
FILE *e;
|
||
|
||
e = xfopen (z, "w");
|
||
|
||
for (i = 0; i < 256; i++)
|
||
{
|
||
int i2;
|
||
|
||
for (i2 = 0; i2 < 256; i2++)
|
||
putc (i, e);
|
||
}
|
||
|
||
for (i = 0; i < c; i++)
|
||
putc (i, e);
|
||
|
||
xfclose (e);
|
||
}
|
||
|
||
/* Check a test file. */
|
||
|
||
static void
|
||
ucheck_file (z, zerr, c)
|
||
const char *z;
|
||
const char *zerr;
|
||
int c;
|
||
{
|
||
int i;
|
||
FILE *e;
|
||
|
||
e = xfopen (z, "r");
|
||
|
||
for (i = 0; i < 256; i++)
|
||
{
|
||
int i2;
|
||
|
||
for (i2 = 0; i2 < 256; i2++)
|
||
{
|
||
int bread;
|
||
|
||
bread = getc (e);
|
||
if (bread == EOF)
|
||
{
|
||
fprintf (stderr,
|
||
"%s: Unexpected EOF at position %d,%d\n",
|
||
zerr, i, i2);
|
||
xfclose (e);
|
||
return;
|
||
}
|
||
if (bread != i)
|
||
fprintf (stderr,
|
||
"%s: At position %d,%d got %d expected %d\n",
|
||
zerr, i, i2, bread, i);
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < c; i++)
|
||
{
|
||
int bread;
|
||
|
||
bread = getc (e);
|
||
if (bread == EOF)
|
||
{
|
||
fprintf (stderr, "%s: Unexpected EOF at extra %d\n", zerr, i);
|
||
xfclose (e);
|
||
return;
|
||
}
|
||
if (bread != i)
|
||
fprintf (stderr, "%s: At extra %d got %d expected %d\n",
|
||
zerr, i, bread, i);
|
||
}
|
||
|
||
if (getc (e) != EOF)
|
||
fprintf (stderr, "%s: File is too long", zerr);
|
||
|
||
xfclose (e);
|
||
}
|
||
|
||
/* Prepare all the configuration files for testing. */
|
||
|
||
static void
|
||
uprepare_test (itest, fcall_uucico, zsys)
|
||
int itest;
|
||
boolean fcall_uucico;
|
||
const char *zsys;
|
||
{
|
||
FILE *e;
|
||
const char *zuucp1, *zuucp2;
|
||
const char *zuux1, *zuux2;
|
||
char ab[1000];
|
||
const char *zfrom;
|
||
const char *zto;
|
||
|
||
/* We must make /usr/tmp/tstuu world writeable or we won't be able to
|
||
receive files into it. */
|
||
|
||
(void) umask (0);
|
||
|
||
#ifndef S_IWOTH
|
||
#define S_IWOTH 02
|
||
#endif
|
||
|
||
if (mkdir ((char *) "/usr/tmp/tstuu",
|
||
IPUBLIC_DIRECTORY_MODE | S_IWOTH) != 0
|
||
&& errno != EEXIST)
|
||
{
|
||
perror ("mkdir");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
if (mkdir ((char *) "/usr/tmp/tstuu/spool1", IPUBLIC_DIRECTORY_MODE) != 0
|
||
&& errno != EEXIST)
|
||
{
|
||
perror ("mkdir");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
if (mkdir ((char *) "/usr/tmp/tstuu/spool2", IPUBLIC_DIRECTORY_MODE) != 0
|
||
&& errno != EEXIST)
|
||
{
|
||
perror ("mkdir");
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/Config1", "w");
|
||
|
||
fprintf (e, "# First test configuration file\n");
|
||
fprintf (e, "nodename test1\n");
|
||
fprintf (e, "spool /usr/tmp/tstuu/spool1\n");
|
||
fprintf (e, "sysfile /usr/tmp/tstuu/System1\n");
|
||
fprintf (e, "sysfile /usr/tmp/tstuu/System1.2\n");
|
||
fprintf (e, "portfile /usr/tmp/tstuu/Port1\n");
|
||
(void) remove ("/usr/tmp/tstuu/Log1");
|
||
#if ! HAVE_BNU_LOGGING
|
||
fprintf (e, "logfile /usr/tmp/tstuu/Log1\n");
|
||
#else
|
||
fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log1/%s/%s");
|
||
#endif
|
||
fprintf (e, "statfile /usr/tmp/tstuu/Stats1\n");
|
||
fprintf (e, "debugfile /usr/tmp/tstuu/Debug1\n");
|
||
fprintf (e, "callfile /usr/tmp/tstuu/Call1\n");
|
||
fprintf (e, "pubdir /usr/tmp/tstuu\n");
|
||
#if HAVE_V2_CONFIG
|
||
fprintf (e, "v2-files no\n");
|
||
#endif
|
||
#if HAVE_BNU_CONFIG
|
||
fprintf (e, "bnu-files no\n");
|
||
#endif
|
||
if (zDebug != NULL)
|
||
fprintf (e, "debug %s\n", zDebug);
|
||
|
||
xfclose (e);
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/System1", "w");
|
||
|
||
fprintf (e, "# This file is ignored, to test multiple system files\n");
|
||
fprintf (e, "time never\n");
|
||
|
||
xfclose (e);
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/System1.2", "w");
|
||
|
||
fprintf (e, "# First test system file\n");
|
||
fprintf (e, "time Any\n");
|
||
fprintf (e, "port stdin\n");
|
||
fprintf (e, "# That was the defaults\n");
|
||
fprintf (e, "system %s\n", zsys);
|
||
if (! fcall_uucico)
|
||
{
|
||
FILE *eprog;
|
||
|
||
eprog = xfopen ("/usr/tmp/tstuu/Chat1", "w");
|
||
|
||
/* Wait for the other side to open the port and flush input. */
|
||
fprintf (eprog, "sleep 1\n");
|
||
fprintf (eprog,
|
||
"echo password $1 speed $2 1>&2\n");
|
||
fprintf (eprog, "echo test1\n");
|
||
fprintf (eprog, "exit 0\n");
|
||
|
||
xfclose (eprog);
|
||
|
||
(void) chmod ("/usr/tmp/tstuu/Chat1", S_IRWXU);
|
||
|
||
fprintf (e, "chat-program /usr/tmp/tstuu/Chat1 \\P \\S\n");
|
||
|
||
fprintf (e, "chat word: \\P\n");
|
||
fprintf (e, "chat-fail login;\n");
|
||
fprintf (e, "call-login *\n");
|
||
fprintf (e, "call-password *\n");
|
||
}
|
||
else
|
||
fprintf (e, "chat \"\"\n");
|
||
fprintf (e, "call-transfer yes\n");
|
||
fprintf (e, "commands cat\n");
|
||
if (! fcall_uucico && iPercent == 0)
|
||
{
|
||
fprintf (e, "protocol-parameter g window 7\n");
|
||
fprintf (e, "protocol-parameter g packet-size 4096\n");
|
||
}
|
||
if (zProtocols != NULL)
|
||
fprintf (e, "protocol %s\n", zProtocols);
|
||
|
||
xfclose (e);
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/Port1", "w");
|
||
|
||
fprintf (e, "port stdin\n");
|
||
fprintf (e, "type stdin\n");
|
||
fprintf (e, "pty true\n");
|
||
|
||
xfclose (e);
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/Call1", "w");
|
||
|
||
fprintf (e, "Call out password file\n");
|
||
fprintf (e, "%s test1 pass1\n", zsys);
|
||
|
||
xfclose (e);
|
||
|
||
if (! fcall_uucico)
|
||
{
|
||
FILE *eprog;
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/Config2", "w");
|
||
|
||
fprintf (e, "# Second test configuration file\n");
|
||
fprintf (e, "nodename test2\n");
|
||
fprintf (e, "spool /usr/tmp/tstuu/spool2\n");
|
||
fprintf (e, "sysfile /usr/tmp/tstuu/System2\n");
|
||
(void) remove ("/usr/tmp/tstuu/Log2");
|
||
#if ! HAVE_BNU_LOGGING
|
||
fprintf (e, "logfile /usr/tmp/tstuu/Log2\n");
|
||
#else
|
||
fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log2/%s/%s");
|
||
#endif
|
||
fprintf (e, "statfile /usr/tmp/tstuu/Stats2\n");
|
||
fprintf (e, "debugfile /usr/tmp/tstuu/Debug2\n");
|
||
fprintf (e, "passwdfile /usr/tmp/tstuu/Pass2\n");
|
||
fprintf (e, "pubdir /usr/tmp/tstuu\n");
|
||
#if HAVE_V2_CONFIG
|
||
fprintf (e, "v2-files no\n");
|
||
#endif
|
||
#if HAVE_BNU_CONFIG
|
||
fprintf (e, "bnu-files no\n");
|
||
#endif
|
||
if (zDebug != NULL)
|
||
fprintf (e, "debug %s\n", zDebug);
|
||
|
||
xfclose (e);
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/System2", "w");
|
||
|
||
fprintf (e, "# Second test system file\n");
|
||
fprintf (e, "system test1\n");
|
||
fprintf (e, "called-login test1\n");
|
||
fprintf (e, "called-request true\n");
|
||
if (zProtocols != NULL)
|
||
fprintf (e, "protocol %s\n", zProtocols);
|
||
|
||
eprog = xfopen ("/usr/tmp/tstuu/Chat2", "w");
|
||
|
||
fprintf (eprog,
|
||
"echo port $1 1>&2\n");
|
||
fprintf (eprog, "exit 0\n");
|
||
|
||
xfclose (eprog);
|
||
|
||
fprintf (e, "called-chat-program /bin/sh /usr/tmp/tstuu/Chat2 \\Y\n");
|
||
fprintf (e, "time Any\n");
|
||
|
||
xfclose (e);
|
||
|
||
e = xfopen ("/usr/tmp/tstuu/Pass2", "w");
|
||
|
||
fprintf (e, "# Call in password file\n");
|
||
fprintf (e, "test1 pass1\n");
|
||
|
||
xfclose (e);
|
||
}
|
||
|
||
zuucp1 = "./uucp -I /usr/tmp/tstuu/Config1 -r";
|
||
zuux1 = "./uux -I /usr/tmp/tstuu/Config1 -r";
|
||
|
||
if (fcall_uucico)
|
||
{
|
||
zuucp2 = "/usr/bin/uucp -r";
|
||
zuux2 = "/usr/bin/uux -r";
|
||
}
|
||
else
|
||
{
|
||
zuucp2 = "./uucp -I /usr/tmp/tstuu/Config2 -r";
|
||
zuux2 = "./uux -I /usr/tmp/tstuu/Config2 -r";
|
||
}
|
||
|
||
/* Test transferring a file from the first system to the second. */
|
||
|
||
if (itest == 0 || itest == 1)
|
||
{
|
||
zfrom = "/usr/tmp/tstuu/from1";
|
||
if (fcall_uucico)
|
||
zto = "/usr/spool/uucppublic/to1";
|
||
else
|
||
zto = "/usr/tmp/tstuu/to1";
|
||
|
||
(void) remove (zto);
|
||
umake_file (zfrom, 0);
|
||
|
||
sprintf (ab, "%s %s %s!%s", zuucp1, zfrom, zsys, zto);
|
||
xsystem (ab);
|
||
}
|
||
|
||
/* Test having the first system request a file from the second. */
|
||
|
||
if (itest == 0 || itest == 2)
|
||
{
|
||
if (fcall_uucico)
|
||
zfrom = "/usr/spool/uucppublic/from2";
|
||
else
|
||
zfrom = "/usr/tmp/tstuu/from2";
|
||
zto = "/usr/tmp/tstuu/to2";
|
||
|
||
(void) remove (zto);
|
||
umake_file (zfrom, 3);
|
||
|
||
sprintf (ab, "%s %s!%s %s", zuucp1, zsys, zfrom, zto);
|
||
xsystem (ab);
|
||
}
|
||
|
||
/* Test having the second system send a file to the first. */
|
||
|
||
if (itest == 0 || itest == 3)
|
||
{
|
||
if (fcall_uucico)
|
||
zfrom = "/usr/spool/uucppublic/from3";
|
||
else
|
||
zfrom = "/usr/tmp/tstuu/from3";
|
||
zto = "/usr/tmp/tstuu/to3";
|
||
|
||
(void) remove (zto);
|
||
umake_file (zfrom, 5);
|
||
|
||
sprintf (ab, "%s -c \\~/from3 test1!~/to3", zuucp2);
|
||
xsystem (ab);
|
||
}
|
||
|
||
/* Test having the second system request a file from the first. */
|
||
|
||
if (itest == 0 || itest == 4)
|
||
{
|
||
zfrom = "/usr/tmp/tstuu/from4";
|
||
if (fcall_uucico)
|
||
zto = "/usr/spool/uucppublic/to4";
|
||
else
|
||
zto = "/usr/tmp/tstuu/to4";
|
||
|
||
(void) remove (zto);
|
||
umake_file (zfrom, 7);
|
||
|
||
sprintf (ab, "%s test1!%s %s", zuucp2, zfrom, zto);
|
||
xsystem (ab);
|
||
}
|
||
|
||
/* Test having the second system make an execution request. */
|
||
|
||
if (itest == 0 || itest == 5)
|
||
{
|
||
zfrom = "/usr/tmp/tstuu/from5";
|
||
if (fcall_uucico)
|
||
zto = "/usr/spool/uucppublic/to5";
|
||
else
|
||
zto = "/usr/tmp/tstuu/to5";
|
||
|
||
(void) remove (zto);
|
||
umake_file (zfrom, 11);
|
||
|
||
sprintf (ab, "%s test1!cat '<%s' '>%s'", zuux2, zfrom, zto);
|
||
xsystem (ab);
|
||
}
|
||
|
||
/* Test having the first system request a wildcard. */
|
||
|
||
if (itest == 0 || itest == 6)
|
||
{
|
||
const char *zfrom1, *zfrom2;
|
||
|
||
if (fcall_uucico)
|
||
{
|
||
zfrom = "/usr/spool/uucppublic/to6\\*";
|
||
zfrom1 = "/usr/spool/uucppublic/to6.1";
|
||
zfrom2 = "/usr/spool/uucppublic/to6.2";
|
||
}
|
||
else
|
||
{
|
||
zfrom = "/usr/tmp/tstuu/spool2/to6\\*";
|
||
zfrom1 = "/usr/tmp/tstuu/spool2/to6.1";
|
||
zfrom2 = "/usr/tmp/tstuu/spool2/to6.2";
|
||
}
|
||
|
||
umake_file (zfrom1, 100);
|
||
umake_file (zfrom2, 101);
|
||
(void) remove ("/usr/tmp/tstuu/to6.1");
|
||
(void) remove ("/usr/tmp/tstuu/to6.2");
|
||
|
||
sprintf (ab, "%s %s!%s /usr/tmp/tstuu", zuucp1, zsys, zfrom);
|
||
xsystem (ab);
|
||
}
|
||
|
||
/* Test having the second system request a wildcard. */
|
||
|
||
if (itest == 0 || itest == 7)
|
||
{
|
||
const char *zto1, *zto2;
|
||
|
||
if (fcall_uucico)
|
||
{
|
||
zto = "/usr/spool/uucppublic";
|
||
zto1 = "/usr/spool/uucppublic/to7.1";
|
||
zto2 = "/usr/spool/uucppublic/to7.2";
|
||
}
|
||
else
|
||
{
|
||
zto = "/usr/tmp/tstuu";
|
||
zto1 = "/usr/tmp/tstuu/to7.1";
|
||
zto2 = "/usr/tmp/tstuu/to7.2";
|
||
}
|
||
|
||
umake_file ("/usr/tmp/tstuu/spool1/to7.1", 150);
|
||
umake_file ("/usr/tmp/tstuu/spool1/to7.2", 155);
|
||
(void) remove (zto1);
|
||
(void) remove (zto2);
|
||
|
||
sprintf (ab, "%s test1!/usr/tmp/tstuu/spool1/to7.\\* %s", zuucp2,
|
||
zto);
|
||
xsystem (ab);
|
||
}
|
||
}
|
||
|
||
/* Try to make sure the file transfers were successful. */
|
||
|
||
static void
|
||
ucheck_test (itest, fcall_uucico)
|
||
int itest;
|
||
boolean fcall_uucico;
|
||
{
|
||
if (itest == 0 || itest == 1)
|
||
{
|
||
if (fcall_uucico)
|
||
ucheck_file ("/usr/spool/uucppublic/to1", "test 1", 0);
|
||
else
|
||
ucheck_file ("/usr/tmp/tstuu/to1", "test 1", 0);
|
||
}
|
||
|
||
if (itest == 0 || itest == 2)
|
||
ucheck_file ("/usr/tmp/tstuu/to2", "test 2", 3);
|
||
|
||
if (itest == 0 || itest == 3)
|
||
ucheck_file ("/usr/tmp/tstuu/to3", "test 3", 5);
|
||
|
||
if (itest == 0 || itest == 4)
|
||
{
|
||
if (fcall_uucico)
|
||
ucheck_file ("/usr/spool/uucppublic/to4", "test 4", 7);
|
||
else
|
||
ucheck_file ("/usr/tmp/tstuu/to4", "test 4", 7);
|
||
}
|
||
|
||
if (itest == 0 || itest == 6)
|
||
{
|
||
ucheck_file ("/usr/tmp/tstuu/to6.1", "test 6.1", 100);
|
||
ucheck_file ("/usr/tmp/tstuu/to6.2", "test 6.2", 101);
|
||
}
|
||
|
||
if (itest == 0 || itest == 7)
|
||
{
|
||
const char *zto1, *zto2;
|
||
|
||
if (fcall_uucico)
|
||
{
|
||
zto1 = "/usr/spool/uucppublic/to7.1";
|
||
zto2 = "/usr/spool/uucppublic/to7.2";
|
||
}
|
||
else
|
||
{
|
||
zto1 = "/usr/tmp/tstuu/to7.1";
|
||
zto2 = "/usr/tmp/tstuu/to7.2";
|
||
}
|
||
|
||
ucheck_file (zto1, "test 7.1", 150);
|
||
ucheck_file (zto2, "test 7.2", 155);
|
||
}
|
||
}
|
||
|
||
/* A debugging routine used when displaying buffers. */
|
||
|
||
static int
|
||
cpshow (z, ichar)
|
||
char *z;
|
||
int ichar;
|
||
{
|
||
if (isprint (BUCHAR (ichar)) && ichar != '\"')
|
||
{
|
||
*z = (char) ichar;
|
||
return 1;
|
||
}
|
||
|
||
*z++ = '\\';
|
||
|
||
switch (ichar)
|
||
{
|
||
case '\n':
|
||
*z = 'n';
|
||
return 2;
|
||
case '\r':
|
||
*z = 'r';
|
||
return 2;
|
||
case '\"':
|
||
*z = '\"';
|
||
return 2;
|
||
default:
|
||
sprintf (z, "%03o", (unsigned int)(ichar & 0xff));
|
||
return strlen (z) + 1;
|
||
}
|
||
}
|
||
|
||
/* Transfer data from one pseudo-terminal to the other. */
|
||
|
||
static void
|
||
utransfer (ofrom, oto, otoslave, pc)
|
||
int ofrom;
|
||
int oto;
|
||
int otoslave;
|
||
int *pc;
|
||
{
|
||
int cread;
|
||
#ifdef FIONREAD
|
||
char abbuf[10000];
|
||
#else
|
||
char abbuf[80];
|
||
#endif
|
||
char *zwrite;
|
||
|
||
cread = read (ofrom, abbuf, sizeof abbuf);
|
||
if (cread < 0)
|
||
{
|
||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||
cread = 0;
|
||
else
|
||
{
|
||
perror ("read");
|
||
uchild (SIGCHLD);
|
||
}
|
||
}
|
||
|
||
if (zDebug != NULL)
|
||
{
|
||
char abshow[325];
|
||
char *zshow;
|
||
int i;
|
||
|
||
zshow = abshow;
|
||
for (i = 0; i < cread && i < 80; i++)
|
||
zshow += cpshow (zshow, abbuf[i]);
|
||
if (i < cread)
|
||
{
|
||
*zshow++ = '.';
|
||
*zshow++ = '.';
|
||
*zshow++ = '.';
|
||
}
|
||
*zshow = '\0';
|
||
fprintf (stderr, "Writing to %d: %d \"%s\"\n", oto, cread, abshow);
|
||
fflush (stderr);
|
||
}
|
||
|
||
if (iPercent > 0)
|
||
{
|
||
int i;
|
||
int c;
|
||
|
||
c = 0;
|
||
for (i = 0; i < cread; i++)
|
||
{
|
||
if (rand () % 100 < iPercent)
|
||
{
|
||
++abbuf[i];
|
||
++c;
|
||
}
|
||
}
|
||
if (zDebug != NULL && c > 0)
|
||
fprintf (stderr, "Clobbered %d bytes\n", c);
|
||
}
|
||
|
||
zwrite = abbuf;
|
||
while (cread > 0)
|
||
{
|
||
long cunread;
|
||
int cdo;
|
||
int cwrote;
|
||
|
||
#ifdef FIONREAD
|
||
if (ioctl (otoslave, FIONREAD, &cunread) < 0)
|
||
{
|
||
perror ("FIONREAD");
|
||
uchild (SIGCHLD);
|
||
}
|
||
if (zDebug != NULL)
|
||
fprintf (stderr, "%ld unread\n", cunread);
|
||
#else /* ! FIONREAD */
|
||
cunread = 0;
|
||
#endif /* ! FIONREAD */
|
||
|
||
cdo = cread;
|
||
if (256 - cunread < cdo)
|
||
{
|
||
cdo = 256 - cunread;
|
||
if (cdo == 0)
|
||
continue;
|
||
}
|
||
|
||
cwrote = write (oto, zwrite, cdo);
|
||
if (cwrote < 0)
|
||
{
|
||
perror ("write");
|
||
uchild (SIGCHLD);
|
||
}
|
||
cread -= cwrote;
|
||
zwrite += cwrote;
|
||
*pc += cwrote;
|
||
}
|
||
}
|
||
|
||
/* A version of the system command that checks for errors. */
|
||
|
||
static void
|
||
xsystem (zcmd)
|
||
const char *zcmd;
|
||
{
|
||
int istat;
|
||
|
||
istat = system ((char *) zcmd);
|
||
if (istat != 0)
|
||
{
|
||
fprintf (stderr, "Command failed with status %d\n", istat);
|
||
fprintf (stderr, "%s\n", zcmd);
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
}
|
||
|
||
/* Pick one of two file descriptors which is ready for reading, or
|
||
return in five seconds. If the argument is ready for reading,
|
||
leave it alone; otherwise set it to -1. */
|
||
|
||
static void
|
||
uchoose (po1, po2)
|
||
int *po1;
|
||
int *po2;
|
||
{
|
||
#if HAVE_SELECT
|
||
|
||
int iread;
|
||
struct timeval stime;
|
||
|
||
iread = (1 << *po1) | (1 << *po2);
|
||
stime.tv_sec = 5;
|
||
stime.tv_usec = 0;
|
||
|
||
if (select ((*po1 > *po2 ? *po1 : *po2) + 1, &iread, (int *) NULL,
|
||
(int *) NULL, &stime) < 0)
|
||
{
|
||
perror ("select");
|
||
uchild (SIGCHLD);
|
||
}
|
||
|
||
if ((iread & (1 << *po1)) == 0)
|
||
*po1 = -1;
|
||
|
||
if ((iread & (1 << *po2)) == 0)
|
||
*po2 = -1;
|
||
|
||
#else /* ! HAVE_SELECT */
|
||
|
||
#if HAVE_POLL
|
||
|
||
struct pollfd as[2];
|
||
|
||
as[0].fd = *po1;
|
||
as[0].events = POLLIN;
|
||
as[1].fd = *po2;
|
||
as[1].events = POLLIN;
|
||
|
||
if (poll (as, 2, 5 * 1000) < 0)
|
||
{
|
||
perror ("poll");
|
||
uchild (SIGCHLD);
|
||
}
|
||
|
||
if ((as[0].revents & POLLIN) == 0)
|
||
*po1 = -1;
|
||
|
||
if ((as[1].revents & POLLIN) == 0)
|
||
*po2 = -1;
|
||
|
||
#endif /* HAVE_POLL */
|
||
#endif /* ! HAVE_SELECT */
|
||
}
|
||
|
||
/* Check whether a file descriptor can be written to. */
|
||
|
||
static boolean
|
||
fwritable (o)
|
||
int o;
|
||
{
|
||
#if HAVE_SELECT
|
||
|
||
int iwrite;
|
||
struct timeval stime;
|
||
int cfds;
|
||
|
||
iwrite = 1 << o;
|
||
|
||
stime.tv_sec = 0;
|
||
stime.tv_usec = 0;
|
||
|
||
cfds = select (o + 1, (int *) NULL, &iwrite, (int *) NULL, &stime);
|
||
if (cfds < 0)
|
||
{
|
||
perror ("select");
|
||
uchild (SIGCHLD);
|
||
}
|
||
|
||
return cfds > 0;
|
||
|
||
#else /* ! HAVE_SELECT */
|
||
|
||
#if HAVE_POLL
|
||
|
||
struct pollfd s;
|
||
int cfds;
|
||
|
||
s.fd = o;
|
||
s.events = POLLOUT;
|
||
|
||
cfds = poll (&s, 1, 0);
|
||
if (cfds < 0)
|
||
{
|
||
perror ("poll");
|
||
uchild (SIGCHLD);
|
||
}
|
||
|
||
return cfds > 0;
|
||
|
||
#endif /* HAVE_POLL */
|
||
#endif /* ! HAVE_SELECT */
|
||
}
|
||
|
||
/* We don't want to link in util.c, since that would bring in the log
|
||
file stuff. Instead, we have local copies of functions that may be
|
||
needed by getopt.c. This should be done in a cleaner way. */
|
||
|
||
#if ! HAVE_MEMCPY && ! HAVE_BCOPY
|
||
|
||
/* Copy one block of memory to another. */
|
||
|
||
pointer
|
||
memcpy (ptoarg, pfromarg, c)
|
||
pointer ptoarg;
|
||
constpointer pfromarg;
|
||
int c;
|
||
{
|
||
char *pto = (char *) ptoarg;
|
||
const char *pfrom = (const char *) pfromarg;
|
||
|
||
while (c-- != 0)
|
||
*pto++ = *pfrom++;
|
||
return ptoarg;
|
||
}
|
||
|
||
#endif /* ! HAVE_MEMCPY && ! HAVE_BCOPY */
|
||
|
||
#if ! HAVE_STRCHR && ! HAVE_INDEX
|
||
|
||
/* Look for a character in a string. This is supposed to work for a
|
||
null byte, although we never actually call it with one. */
|
||
|
||
char *
|
||
strchr (z, b)
|
||
const char *z;
|
||
int b;
|
||
{
|
||
b = (char) b;
|
||
while (*z != b)
|
||
if (*z++ == '\0')
|
||
return NULL;
|
||
return (char *) z;
|
||
}
|
||
|
||
#endif /* ! HAVE_STRCHR && ! HAVE_INDEX */
|