1/* tstuu.c 2 Test the uucp package on a UNIX system. 3 4 Copyright (C) 1991, 1992, 1993, 1994, 1995, 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 21 22 The author of the program may be contacted at ian@airs.com. 23 */ 24 25#include "uucp.h" 26 27#if USE_RCS_ID 28const char tstuu_rcsid[] = "$Id: tstuu.c,v 1.89 2002/03/05 19:10:41 ian Rel $"; 29#endif 30 31#include "sysdep.h" 32#include "system.h" 33#include "getopt.h" 34 35#include <stdio.h> 36#include <ctype.h> 37#include <errno.h> 38 39#if HAVE_SYS_TIMES_H 40#include <sys/times.h> 41#endif 42 43#if HAVE_SYS_IOCTL_H 44#include <sys/ioctl.h> 45#endif 46 47#if HAVE_SELECT 48#if HAVE_SYS_TIME_H 49#include <sys/time.h> 50#endif 51#if HAVE_SYS_SELECT_H 52#include <sys/select.h> 53#endif 54#endif 55 56#if HAVE_POLL 57#if HAVE_STROPTS_H 58#include <stropts.h> 59#endif 60#if HAVE_POLL_H 61#include <poll.h> 62#endif 63#endif 64 65#if HAVE_FCNTL_H 66#include <fcntl.h> 67#else 68#if HAVE_SYS_FILE_H 69#include <sys/file.h> 70#endif 71#endif 72 73#ifndef O_RDONLY 74#define O_RDONLY 0 75#define O_WRONLY 1 76#define O_RDWR 2 77#endif 78 79#if HAVE_TIME_H 80#if ! HAVE_SYS_TIME_H || ! HAVE_SELECT || TIME_WITH_SYS_TIME 81#include <time.h> 82#endif 83#endif 84 85#if HAVE_SYS_WAIT_H 86#include <sys/wait.h> 87#endif 88 89#if HAVE_UNION_WAIT 90typedef union wait wait_status; 91#else 92typedef int wait_status; 93#endif 94 95#if HAVE_STREAMS_PTYS 96#include <termio.h> 97extern char *ptsname (); 98#endif 99 100/* Get definitions for both O_NONBLOCK and O_NDELAY. */ 101 102#ifndef O_NDELAY 103#ifdef FNDELAY 104#define O_NDELAY FNDELAY 105#else /* ! defined (FNDELAY) */ 106#define O_NDELAY 0 107#endif /* ! defined (FNDELAY) */ 108#endif /* ! defined (O_NDELAY) */ 109 110#ifndef O_NONBLOCK 111#ifdef FNBLOCK 112#define O_NONBLOCK FNBLOCK 113#else /* ! defined (FNBLOCK) */ 114#define O_NONBLOCK 0 115#endif /* ! defined (FNBLOCK) */ 116#endif /* ! defined (O_NONBLOCK) */ 117 118#if O_NDELAY == 0 && O_NONBLOCK == 0 119 #error No way to do nonblocking I/O 120#endif 121 122/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */ 123#ifndef EAGAIN 124#ifndef EWOULDBLOCK 125#define EAGAIN (-1) 126#define EWOULDBLOCK (-1) 127#else /* defined (EWOULDBLOCK) */ 128#define EAGAIN EWOULDBLOCK 129#endif /* defined (EWOULDBLOCK) */ 130#else /* defined (EAGAIN) */ 131#ifndef EWOULDBLOCK 132#define EWOULDBLOCK EAGAIN 133#endif /* ! defined (EWOULDBLOCK) */ 134#endif /* defined (EAGAIN) */ 135 136#ifndef ENODATA 137#define ENODATA EAGAIN 138#endif 139 140/* Make sure we have a CLK_TCK definition, even if it makes no sense. 141 This is in case TIMES_TICK is defined as CLK_TCK. */ 142#ifndef CLK_TCK 143#define CLK_TCK (60) 144#endif 145 146/* Don't try too hard to get a TIMES_TICK value; it doesn't matter 147 that much. */ 148#if TIMES_TICK == 0 149#undef TIMES_TICK 150#define TIMES_TICK CLK_TCK 151#endif 152 153#if TIMES_DECLARATION_OK 154extern long times (); 155#endif 156 157#ifndef SIGCHLD 158#define SIGCHLD SIGCLD 159#endif 160 161#if 1 162#define ZUUCICO_CMD "login uucp" 163#define UUCICO_EXECL "/bin/login", "login", "uucp" 164#else 165#define ZUUCICO_CMD "su - nuucp" 166#define UUCICO_EXECL "/bin/su", "su", "-", "nuucp" 167#endif 168 169#if ! HAVE_SELECT && ! HAVE_POLL 170 #error You need select or poll 171#endif 172 173#if ! HAVE_REMOVE 174#undef remove 175#define remove unlink 176#endif 177 178/* Buffer chain to hold data read from a uucico. */ 179 180#define BUFCHARS (512) 181 182struct sbuf 183{ 184 struct sbuf *qnext; 185 int cstart; 186 int cend; 187 char ab[BUFCHARS]; 188}; 189 190/* Local functions. */ 191 192static void umake_file P((const char *zfile, int cextra)); 193static void uprepare_test P((boolean fmake, int itest, 194 boolean fcall_uucico, 195 const char *zsys)); 196static void ucheck_file P((const char *zfile, const char *zerr, 197 int cextra)); 198static void ucheck_test P((int itest, boolean fcall_uucico)); 199static RETSIGTYPE uchild P((int isig)); 200static int cpshow P((char *z, int bchar)); 201static void uchoose P((int *po1, int *po2)); 202static long cread P((int o, struct sbuf **)); 203static boolean fsend P((int o, int oslave, struct sbuf **)); 204static boolean fwritable P((int o)); 205static void xsystem P((const char *zcmd)); 206static FILE *xfopen P((const char *zname, const char *zmode)); 207 208static char *zDebug; 209static int iTest; 210static boolean fCall_uucico; 211static int iPercent; 212static pid_t iPid1, iPid2; 213static int cFrom1, cFrom2; 214static char abLogout1[sizeof "tstout /dev/ptyp0"]; 215static char abLogout2[sizeof "tstout /dev/ptyp0"]; 216static char *zProtocols; 217 218int 219main (argc, argv) 220 int argc; 221 char **argv; 222{ 223 int iopt; 224 const char *zcmd1, *zcmd2; 225 const char *zsys; 226 boolean fmake = TRUE; 227 int omaster1, oslave1, omaster2, oslave2; 228 char abpty1[sizeof "/dev/ptyp0"]; 229 char abpty2[sizeof "/dev/ptyp0"]; 230 struct sbuf *qbuf1, *qbuf2; 231 232#if ! HAVE_TAYLOR_CONFIG 233 fprintf (stderr, "%s: only works when compiled with HAVE_TAYLOR_CONFIG\n", 234 argv[0]); 235 exit (1); 236#endif 237 238 zcmd1 = NULL; 239 zcmd2 = NULL; 240 zsys = "test2"; 241 242 while ((iopt = getopt (argc, argv, "c:np:s:t:ux:1:2:")) != EOF) 243 { 244 switch (iopt) 245 { 246 case 'c': 247 zProtocols = optarg; 248 break; 249 case 'n': 250 fmake = FALSE; 251 break; 252 case 'p': 253 iPercent = (int) strtol (optarg, (char **) NULL, 10); 254 srand ((unsigned int) ixsysdep_time ((long *) NULL)); 255 break; 256 case 's': 257 zsys = optarg; 258 break; 259 case 't': 260 iTest = (int) strtol (optarg, (char **) NULL, 10); 261 break; 262 case 'u': 263 fCall_uucico = TRUE; 264 break; 265 case 'x': 266 zDebug = optarg; 267 break; 268 case '1': 269 zcmd1 = optarg; 270 break; 271 case '2': 272 zcmd2 = optarg; 273 break; 274 default: 275 fprintf (stderr, 276 "Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n", 277 VERSION); 278 fprintf (stderr, 279 "Usage: tstuu [-xn] [-t #] [-u] [-1 cmd] [-2 cmd]\n"); 280 exit (EXIT_FAILURE); 281 } 282 } 283 284 if (fCall_uucico && zcmd2 == NULL) 285 zcmd2 = ZUUCICO_CMD; 286 287 uprepare_test (fmake, iTest, fCall_uucico, zsys); 288 289 (void) remove ("/usr/tmp/tstuu/spool1/core"); 290 (void) remove ("/usr/tmp/tstuu/spool2/core"); 291 292 omaster1 = -1; 293 oslave1 = -1; 294 omaster2 = -1; 295 oslave2 = -1; 296 297#if ! HAVE_STREAMS_PTYS 298 299 { 300 char *zptyname; 301 const char *zpty; 302 303 zptyname = abpty1; 304 305 for (zpty = "pqrs"; *zpty != '\0'; ++zpty) 306 { 307 int ipty; 308 309 for (ipty = 0; ipty < 16; ipty++) 310 { 311 int om, os; 312 FILE *e; 313 314 sprintf (zptyname, "/dev/pty%c%c", *zpty, 315 "0123456789abcdef"[ipty]); 316 om = open (zptyname, O_RDWR); 317 if (om < 0) 318 continue; 319 zptyname[5] = 't'; 320 os = open (zptyname, O_RDWR); 321 if (os < 0) 322 { 323 (void) close (om); 324 continue; 325 } 326 327 if (omaster1 == -1) 328 { 329 omaster1 = om; 330 oslave1 = os; 331 332 e = fopen ("/usr/tmp/tstuu/pty1", "w"); 333 if (e == NULL) 334 { 335 perror ("fopen"); 336 exit (EXIT_FAILURE); 337 } 338 fprintf (e, "%s", zptyname + 5); 339 if (fclose (e) != 0) 340 { 341 perror ("fclose"); 342 exit (EXIT_FAILURE); 343 } 344 345 zptyname = abpty2; 346 } 347 else 348 { 349 omaster2 = om; 350 oslave2 = os; 351 352 e = fopen ("/usr/tmp/tstuu/pty2", "w"); 353 if (e == NULL) 354 { 355 perror ("fopen"); 356 exit (EXIT_FAILURE); 357 } 358 fprintf (e, "%s", zptyname + 5); 359 if (fclose (e) != 0) 360 { 361 perror ("fclose"); 362 exit (EXIT_FAILURE); 363 } 364 break; 365 } 366 } 367 368 if (omaster1 != -1 && omaster2 != -1) 369 break; 370 } 371 } 372 373#else /* HAVE_STREAMS_PTYS */ 374 375 { 376 int ipty; 377 378 for (ipty = 0; ipty < 2; ipty++) 379 { 380 int om, os; 381 FILE *e; 382 char *znam; 383 struct termio stio; 384 385 om = open ((char *) "/dev/ptmx", O_RDWR); 386 if (om < 0) 387 break; 388 znam = ptsname (om); 389 if (znam == NULL) 390 break; 391 if (unlockpt (om) != 0 392 || grantpt (om) != 0) 393 break; 394 395 os = open (znam, O_RDWR); 396 if (os < 0) 397 { 398 (void) close (om); 399 om = -1; 400 break; 401 } 402 403 if (ioctl (os, I_PUSH, "ptem") < 0 404 || ioctl(os, I_PUSH, "ldterm") < 0) 405 { 406 perror ("ioctl"); 407 exit (EXIT_FAILURE); 408 } 409 410 /* Can this really be right? */ 411 memset (&stio, 0, sizeof (stio)); 412 stio.c_cflag = B9600 | CS8 | CREAD | HUPCL; 413 414 if (ioctl(os, TCSETA, &stio) < 0) 415 { 416 perror ("TCSETA"); 417 exit (EXIT_FAILURE); 418 } 419 420 if (omaster1 == -1) 421 { 422 strcpy (abpty1, znam); 423 omaster1 = om; 424 oslave1 = os; 425 e = fopen ("/usr/tmp/tstuu/pty1", "w"); 426 if (e == NULL) 427 { 428 perror ("fopen"); 429 exit (EXIT_FAILURE); 430 } 431 fprintf (e, "%s", znam + 5); 432 if (fclose (e) != 0) 433 { 434 perror ("fclose"); 435 exit (EXIT_FAILURE); 436 } 437 } 438 else 439 { 440 strcpy (abpty2, znam); 441 omaster2 = om; 442 oslave2 = os; 443 e = fopen ("/usr/tmp/tstuu/pty2", "w"); 444 if (e == NULL) 445 { 446 perror ("fopen"); 447 exit (EXIT_FAILURE); 448 } 449 fprintf (e, "%s", znam + 5); 450 if (fclose (e) != 0) 451 { 452 perror ("fclose"); 453 exit (EXIT_FAILURE); 454 } 455 } 456 } 457 } 458 459#endif /* HAVE_STREAMS_PTYS */ 460 461 if (omaster2 == -1) 462 { 463 fprintf (stderr, "No pseudo-terminals available\n"); 464 exit (EXIT_FAILURE); 465 } 466 467 /* Make sure we can or these into an int for the select call. Most 468 systems could use 31 instead of 15, but it should never be a 469 problem. */ 470 if (omaster1 > 15 || omaster2 > 15) 471 { 472 fprintf (stderr, "File descriptors are too large\n"); 473 exit (EXIT_FAILURE); 474 } 475 476 /* Prepare to log out the command if it is a login command. On 477 Ultrix 4.0 uucico can only be run from login for some reason. */ 478 479 if (zcmd1 == NULL 480 || strncmp (zcmd1, "login", sizeof "login" - 1) != 0) 481 abLogout1[0] = '\0'; 482 else 483 sprintf (abLogout1, "tstout %s", abpty1); 484 485 if (zcmd2 == NULL 486 || strncmp (zcmd2, "login", sizeof "login" - 1) != 0) 487 abLogout2[0] = '\0'; 488 else 489 sprintf (abLogout2, "tstout %s", abpty2); 490 491 iPid1 = fork (); 492 if (iPid1 < 0) 493 { 494 perror ("fork"); 495 exit (EXIT_FAILURE); 496 } 497 else if (iPid1 == 0) 498 { 499 if (close (0) < 0 500 || close (1) < 0 501 || close (omaster1) < 0 502 || close (omaster2) < 0 503 || close (oslave2) < 0) 504 perror ("close"); 505 506 if (dup2 (oslave1, 0) < 0 507 || dup2 (oslave1, 1) < 0) 508 perror ("dup2"); 509 510 if (close (oslave1) < 0) 511 perror ("close"); 512 513 /* This is said to improve the tests on Linux. */ 514 sleep (3); 515 516 if (zDebug != NULL) 517 fprintf (stderr, "About to exec first process\n"); 518 519 if (zcmd1 != NULL) 520 exit (system ((char *) zcmd1)); 521 else 522 { 523 (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config1", 524 "-q", "-S", zsys, "-pstdin", (const char *) NULL); 525 perror ("execl failed"); 526 exit (EXIT_FAILURE); 527 } 528 } 529 530 iPid2 = fork (); 531 if (iPid2 < 0) 532 { 533 perror ("fork"); 534 kill (iPid1, SIGTERM); 535 exit (EXIT_FAILURE); 536 } 537 else if (iPid2 == 0) 538 { 539 if (close (0) < 0 540 || close (1) < 0 541 || close (omaster1) < 0 542 || close (oslave1) < 0 543 || close (omaster2) < 0) 544 perror ("close"); 545 546 if (dup2 (oslave2, 0) < 0 547 || dup2 (oslave2, 1) < 0) 548 perror ("dup2"); 549 550 if (close (oslave2) < 0) 551 perror ("close"); 552 553 /* This is said to improve the tests on Linux. */ 554 sleep (5); 555 556 if (zDebug != NULL) 557 fprintf (stderr, "About to exec second process\n"); 558 559 if (fCall_uucico) 560 { 561 (void) execl (UUCICO_EXECL, (const char *) NULL); 562 perror ("execl failed"); 563 exit (EXIT_FAILURE); 564 } 565 else if (zcmd2 != NULL) 566 exit (system ((char *) zcmd2)); 567 else 568 { 569 (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config2", 570 "-lq", (const char *)NULL); 571 perror ("execl failed"); 572 exit (EXIT_FAILURE); 573 } 574 } 575 576 signal (SIGCHLD, uchild); 577 578 if (fcntl (omaster1, F_SETFL, O_NDELAY | O_NONBLOCK) < 0 579 && errno == EINVAL) 580 (void) fcntl (omaster1, F_SETFL, O_NONBLOCK); 581 if (fcntl (omaster2, F_SETFL, O_NDELAY | O_NONBLOCK) < 0 582 && errno == EINVAL) 583 (void) fcntl (omaster2, F_SETFL, O_NONBLOCK); 584 585 qbuf1 = NULL; 586 qbuf2 = NULL; 587 588 while (TRUE) 589 { 590 int o1, o2; 591 boolean fcont; 592 593 o1 = omaster1; 594 o2 = omaster2; 595 uchoose (&o1, &o2); 596 597 if (o1 == -1 && o2 == -1) 598 { 599 if (zDebug != NULL) 600 fprintf (stderr, "Five second pause\n"); 601 continue; 602 } 603 604 if (o1 != -1) 605 cFrom1 += cread (omaster1, &qbuf1); 606 607 if (o2 != -1) 608 cFrom2 += cread (omaster2, &qbuf2); 609 610 do 611 { 612 fcont = FALSE; 613 614 if (qbuf1 != NULL 615 && fwritable (omaster2) 616 && fsend (omaster2, oslave2, &qbuf1)) 617 fcont = TRUE; 618 619 if (qbuf2 != NULL 620 && fwritable (omaster1) 621 && fsend (omaster1, oslave1, &qbuf2)) 622 fcont = TRUE; 623 624 if (! fcont 625 && (qbuf1 != NULL || qbuf2 != NULL)) 626 { 627 long cgot1, cgot2; 628 629 cgot1 = cread (omaster1, &qbuf1); 630 cFrom1 += cgot1; 631 cgot2 = cread (omaster2, &qbuf2); 632 cFrom2 += cgot2; 633 fcont = TRUE; 634 } 635 } 636 while (fcont); 637 } 638 639 /*NOTREACHED*/ 640} 641 642/* When a child dies, kill them both. */ 643 644static RETSIGTYPE 645uchild (isig) 646 int isig ATTRIBUTE_UNUSED; 647{ 648 struct tms sbase, s1, s2; 649 650 signal (SIGCHLD, SIG_DFL); 651 652 /* Give the processes a chance to die on their own. */ 653 sleep (2); 654 655 (void) kill (iPid1, SIGTERM); 656 (void) kill (iPid2, SIGTERM); 657 658 (void) times (&sbase); 659 660#if HAVE_WAITPID 661 (void) waitpid (iPid1, (pointer) NULL, 0); 662#else /* ! HAVE_WAITPID */ 663#if HAVE_WAIT4 664 (void) wait4 (iPid1, (pointer) NULL, 0, (struct rusage *) NULL); 665#else /* ! HAVE_WAIT4 */ 666 (void) wait ((wait_status *) NULL); 667#endif /* ! HAVE_WAIT4 */ 668#endif /* ! HAVE_WAITPID */ 669 670 (void) times (&s1); 671 672#if HAVE_WAITPID 673 (void) waitpid (iPid2, (pointer) NULL, 0); 674#else /* ! HAVE_WAITPID */ 675#if HAVE_WAIT4 676 (void) wait4 (iPid2, (wait_status *) NULL, 0, (struct rusage *) NULL); 677#else /* ! HAVE_WAIT4 */ 678 (void) wait ((wait_status *) NULL); 679#endif /* ! HAVE_WAIT4 */ 680#endif /* ! HAVE_WAITPID */ 681 682 (void) times (&s2); 683 684 fprintf (stderr, 685 " First child: user: %g; system: %g\n", 686 (double) (s1.tms_cutime - sbase.tms_cutime) / (double) TIMES_TICK, 687 (double) (s1.tms_cstime - sbase.tms_cstime) / (double) TIMES_TICK); 688 fprintf (stderr, 689 "Second child: user: %g; system: %g\n", 690 (double) (s2.tms_cutime - s1.tms_cutime) / (double) TIMES_TICK, 691 (double) (s2.tms_cstime - s1.tms_cstime) / (double) TIMES_TICK); 692 693 ucheck_test (iTest, fCall_uucico); 694 695 if (abLogout1[0] != '\0') 696 { 697 if (zDebug != NULL) 698 fprintf (stderr, "Executing %s\n", abLogout1); 699 (void) system (abLogout1); 700 } 701 if (abLogout2[0] != '\0') 702 { 703 if (zDebug != NULL) 704 fprintf (stderr, "Executing %s\n", abLogout2); 705 (void) system (abLogout2); 706 } 707 708 fprintf (stderr, "Wrote %d bytes from 1 to 2\n", cFrom1); 709 fprintf (stderr, "Wrote %d bytes from 2 to 1\n", cFrom2); 710 711 if (access ("/usr/tmp/tstuu/spool1/core", R_OK) == 0) 712 fprintf (stderr, "core file 1 exists\n"); 713 if (access ("/usr/tmp/tstuu/spool2/core", R_OK) == 0) 714 fprintf (stderr, "core file 2 exists\n"); 715 716 exit (EXIT_SUCCESS); 717} 718 719/* Open a file without error. */ 720 721static FILE * 722xfopen (zname, zmode) 723 const char *zname; 724 const char *zmode; 725{ 726 FILE *eret; 727 728 eret = fopen (zname, zmode); 729 if (eret == NULL) 730 { 731 perror (zname); 732 exit (EXIT_FAILURE); 733 } 734 return eret; 735} 736 737/* Close a file without error. */ 738 739static void xfclose P((FILE *e)); 740 741static void 742xfclose (e) 743 FILE *e; 744{ 745 if (fclose (e) != 0) 746 { 747 perror ("fclose"); 748 exit (EXIT_FAILURE); 749 } 750} 751 752/* Create a test file. */ 753 754static void 755umake_file (z, c) 756 const char *z; 757 int c; 758{ 759 int i; 760 FILE *e; 761 762 e = xfopen (z, "w"); 763 764 for (i = 0; i < 256; i++) 765 { 766 int i2; 767 768 for (i2 = 0; i2 < 256; i2++) 769 putc (i, e); 770 } 771 772 for (i = 0; i < c; i++) 773 putc (i, e); 774 775 xfclose (e); 776} 777 778/* Check a test file. */ 779 780static void 781ucheck_file (z, zerr, c) 782 const char *z; 783 const char *zerr; 784 int c; 785{ 786 int i; 787 FILE *e; 788 789 e = xfopen (z, "r"); 790 791 for (i = 0; i < 256; i++) 792 { 793 int i2; 794 795 for (i2 = 0; i2 < 256; i2++) 796 { 797 int bread; 798 799 bread = getc (e); 800 if (bread == EOF) 801 { 802 fprintf (stderr, 803 "%s: Unexpected EOF at position %d,%d\n", 804 zerr, i, i2); 805 xfclose (e); 806 return; 807 } 808 if (bread != i) 809 fprintf (stderr, 810 "%s: At position %d,%d got %d expected %d\n", 811 zerr, i, i2, bread, i); 812 } 813 } 814 815 for (i = 0; i < c; i++) 816 { 817 int bread; 818 819 bread = getc (e); 820 if (bread == EOF) 821 { 822 fprintf (stderr, "%s: Unexpected EOF at extra %d\n", zerr, i); 823 xfclose (e); 824 return; 825 } 826 if (bread != i) 827 fprintf (stderr, "%s: At extra %d got %d expected %d\n", 828 zerr, i, bread, i); 829 } 830 831 if (getc (e) != EOF) 832 fprintf (stderr, "%s: File is too long", zerr); 833 834 xfclose (e); 835} 836 837/* Prepare all the configuration files for testing. */ 838 839static void 840uprepare_test (fmake, itest, fcall_uucico, zsys) 841 boolean fmake; 842 int itest; 843 boolean fcall_uucico; 844 const char *zsys; 845{ 846 FILE *e; 847 const char *zuucp1, *zuucp2; 848 const char *zuux1, *zuux2; 849 char ab[1000]; 850 const char *zfrom; 851 const char *zto; 852 853/* We must make /usr/tmp/tstuu world writeable or we won't be able to 854 receive files into it. */ 855 (void) umask (0); 856 857#ifndef S_IWOTH 858#define S_IWOTH 02 859#endif 860 861 if (mkdir ((char *) "/usr/tmp/tstuu", 862 IPUBLIC_DIRECTORY_MODE | S_IWOTH) != 0 863 && errno != EEXIST) 864 { 865 perror ("mkdir"); 866 exit (EXIT_FAILURE); 867 } 868 869 if (mkdir ((char *) "/usr/tmp/tstuu/spool1", IPUBLIC_DIRECTORY_MODE) != 0 870 && errno != EEXIST) 871 { 872 perror ("mkdir"); 873 exit (EXIT_FAILURE); 874 } 875 876 if (mkdir ((char *) "/usr/tmp/tstuu/spool2", IPUBLIC_DIRECTORY_MODE) != 0 877 && errno != EEXIST) 878 { 879 perror ("mkdir"); 880 exit (EXIT_FAILURE); 881 } 882 883 if (fmake) 884 { 885 e = xfopen ("/usr/tmp/tstuu/Config1", "w"); 886 887 fprintf (e, "# First test configuration file\n"); 888 fprintf (e, "nodename test1\n"); 889 fprintf (e, "spool /usr/tmp/tstuu/spool1\n"); 890 fprintf (e, "lockdir /usr/tmp/tstuu/spool1\n"); 891 fprintf (e, "sysfile /usr/tmp/tstuu/System1\n"); 892 fprintf (e, "sysfile /usr/tmp/tstuu/System1.2\n"); 893 fprintf (e, "portfile /usr/tmp/tstuu/Port1\n"); 894 (void) remove ("/usr/tmp/tstuu/Log1"); 895#if ! HAVE_HDB_LOGGING 896 fprintf (e, "logfile /usr/tmp/tstuu/Log1\n"); 897#else 898 fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log1/%s/%s"); 899#endif 900 fprintf (e, "statfile /usr/tmp/tstuu/Stats1\n"); 901 fprintf (e, "debugfile /usr/tmp/tstuu/Debug1\n"); 902 fprintf (e, "callfile /usr/tmp/tstuu/Call1\n"); 903 fprintf (e, "pubdir /usr/tmp/tstuu\n"); 904#if HAVE_V2_CONFIG 905 fprintf (e, "v2-files no\n"); 906#endif 907#if HAVE_HDB_CONFIG 908 fprintf (e, "hdb-files no\n"); 909#endif 910 if (zDebug != NULL) 911 fprintf (e, "debug %s\n", zDebug); 912 913 xfclose (e); 914 915 e = xfopen ("/usr/tmp/tstuu/System1", "w"); 916 917 fprintf (e, "# This file is ignored, to test multiple system files\n"); 918 fprintf (e, "time never\n"); 919 920 xfclose (e); 921 922 e = xfopen ("/usr/tmp/tstuu/System1.2", "w"); 923 924 fprintf (e, "# First test system file\n"); 925 fprintf (e, "time any\n"); 926 fprintf (e, "port stdin\n"); 927 fprintf (e, "# That was the defaults\n"); 928 fprintf (e, "system %s\n", zsys); 929 if (! fcall_uucico) 930 { 931 FILE *eprog; 932 933 eprog = xfopen ("/usr/tmp/tstuu/Chat1", "w"); 934 935 /* Wait for the other side to open the port and flush input. */ 936 fprintf (eprog, "sleep 2\n"); 937 fprintf (eprog, 938 "echo password $1 speed $2 1>&2\n"); 939 fprintf (eprog, "echo test1\n"); 940 fprintf (eprog, "exit 0\n"); 941 942 xfclose (eprog); 943 944 if (chmod ("/usr/tmp/tstuu/Chat1", 945 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) 946 { 947 perror ("chmod (/usr/tmp/tstuu/Chat1)"); 948 exit (EXIT_FAILURE); 949 } 950 951 fprintf (e, "chat-program /usr/tmp/tstuu/Chat1 \\P \\S\n"); 952 953 fprintf (e, "chat word: \\P\n"); 954 fprintf (e, "chat-fail login;\n"); 955 fprintf (e, "call-login *\n"); 956 fprintf (e, "call-password *\n"); 957 } 958 else 959 fprintf (e, "chat \"\"\n"); 960 fprintf (e, "call-transfer yes\n"); 961 fprintf (e, "commands cat\n"); 962 if (! fcall_uucico && iPercent == 0) 963 { 964 fprintf (e, "protocol-parameter g window 7\n"); 965 fprintf (e, "protocol-parameter g packet-size 4096\n"); 966 fprintf (e, "protocol-parameter j avoid \\377\n"); 967 } 968 if (zProtocols != NULL) 969 fprintf (e, "protocol %s\n", zProtocols); 970 971 xfclose (e); 972 973 e = xfopen ("/usr/tmp/tstuu/Port1", "w"); 974 975 fprintf (e, "port stdin\n"); 976 fprintf (e, "type stdin\n"); 977 978 xfclose (e); 979 980 e = xfopen ("/usr/tmp/tstuu/Call1", "w"); 981 982 fprintf (e, "Call out password file\n"); 983 fprintf (e, "%s test1 pass\\s1\n", zsys); 984 985 xfclose (e); 986 987 if (! fcall_uucico) 988 { 989 FILE *eprog; 990 991 e = xfopen ("/usr/tmp/tstuu/Config2", "w"); 992 993 fprintf (e, "# Second test configuration file\n"); 994 fprintf (e, "nodename test2\n"); 995 fprintf (e, "spool /usr/tmp/tstuu/spool2\n"); 996 fprintf (e, "lockdir /usr/tmp/tstuu/spool2\n"); 997 fprintf (e, "sysfile /usr/tmp/tstuu/System2\n"); 998 (void) remove ("/usr/tmp/tstuu/Log2"); 999#if ! HAVE_HDB_LOGGING 1000 fprintf (e, "logfile /usr/tmp/tstuu/Log2\n"); 1001#else 1002 fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log2/%s/%s"); 1003#endif 1004 fprintf (e, "statfile /usr/tmp/tstuu/Stats2\n"); 1005 fprintf (e, "debugfile /usr/tmp/tstuu/Debug2\n"); 1006 fprintf (e, "passwdfile /usr/tmp/tstuu/Pass2\n"); 1007 fprintf (e, "pubdir /usr/tmp/tstuu\n"); 1008#if HAVE_V2_CONFIG 1009 fprintf (e, "v2-files no\n"); 1010#endif 1011#if HAVE_HDB_CONFIG 1012 fprintf (e, "hdb-files no\n"); 1013#endif 1014 if (zDebug != NULL) 1015 fprintf (e, "debug %s\n", zDebug); 1016 1017 xfclose (e); 1018 1019 e = xfopen ("/usr/tmp/tstuu/System2", "w"); 1020 1021 fprintf (e, "# Second test system file\n"); 1022 fprintf (e, "system test1\n"); 1023 fprintf (e, "called-login test1\n"); 1024 fprintf (e, "request true\n"); 1025 fprintf (e, "commands cat\n"); 1026 if (zProtocols != NULL) 1027 fprintf (e, "protocol %s\n", zProtocols); 1028 1029 eprog = xfopen ("/usr/tmp/tstuu/Chat2", "w"); 1030 1031 fprintf (eprog, 1032 "echo port $1 1>&2\n"); 1033 fprintf (eprog, "exit 0\n"); 1034 1035 xfclose (eprog); 1036 1037 if (chmod ("/usr/tmp/tstuu/Chat2", 1038 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) 1039 { 1040 perror ("chmod (/usr/tmp/tstuu/Chat2"); 1041 exit (EXIT_FAILURE); 1042 } 1043 1044 fprintf (e, "called-chat-program /bin/sh /usr/tmp/tstuu/Chat2 \\Y\n"); 1045 fprintf (e, "time any\n"); 1046 1047 xfclose (e); 1048 1049 e = xfopen ("/usr/tmp/tstuu/Pass2", "w"); 1050 1051 fprintf (e, "# Call in password file\n"); 1052 fprintf (e, "test1 pass\\s1\n"); 1053 1054 xfclose (e); 1055 } 1056 } 1057 1058 zuucp1 = "./uucp -I /usr/tmp/tstuu/Config1 -r"; 1059 zuux1 = "./uux -I /usr/tmp/tstuu/Config1 -r"; 1060 1061 if (fcall_uucico) 1062 { 1063 zuucp2 = "/usr/bin/uucp -r"; 1064 zuux2 = "/usr/bin/uux -r"; 1065 } 1066 else 1067 { 1068 zuucp2 = "./uucp -I /usr/tmp/tstuu/Config2 -r"; 1069 zuux2 = "./uux -I /usr/tmp/tstuu/Config2 -r"; 1070 } 1071 1072 /* Test transferring a file from the first system to the second. */ 1073 if (itest == 0 || itest == 1) 1074 { 1075 zfrom = "/usr/tmp/tstuu/from1"; 1076 if (fcall_uucico) 1077 zto = "/usr/spool/uucppublic/to1"; 1078 else 1079 zto = "/usr/tmp/tstuu/to1"; 1080 1081 (void) remove (zto); 1082 umake_file (zfrom, 0); 1083 1084 sprintf (ab, "%s %s %s!%s", zuucp1, zfrom, zsys, zto); 1085 xsystem (ab); 1086 } 1087 1088 /* Test having the first system request a file from the second. */ 1089 if (itest == 0 || itest == 2) 1090 { 1091 if (fcall_uucico) 1092 zfrom = "/usr/spool/uucppublic/from2"; 1093 else 1094 zfrom = "/usr/tmp/tstuu/from2"; 1095 zto = "/usr/tmp/tstuu/to2"; 1096 1097 (void) remove (zto); 1098 umake_file (zfrom, 3); 1099 1100 sprintf (ab, "%s %s!%s %s", zuucp1, zsys, zfrom, zto); 1101 xsystem (ab); 1102 } 1103 1104 /* Test having the second system send a file to the first. */ 1105 if (itest == 0 || itest == 3) 1106 { 1107 if (fcall_uucico) 1108 zfrom = "/usr/spool/uucppublic/from3"; 1109 else 1110 zfrom = "/usr/tmp/tstuu/from3"; 1111 zto = "/usr/tmp/tstuu/to3"; 1112 1113 (void) remove (zto); 1114 umake_file (zfrom, 5); 1115 1116 sprintf (ab, "%s -c \\~/from3 test1!~/to3", zuucp2); 1117 xsystem (ab); 1118 } 1119 1120 /* Test having the second system request a file from the first. */ 1121 if (itest == 0 || itest == 4) 1122 { 1123 zfrom = "/usr/tmp/tstuu/from4"; 1124 if (fcall_uucico) 1125 zto = "/usr/spool/uucppublic/to4"; 1126 else 1127 zto = "/usr/tmp/tstuu/to4"; 1128 1129 (void) remove (zto); 1130 umake_file (zfrom, 7); 1131 1132 sprintf (ab, "%s test1!%s %s", zuucp2, zfrom, zto); 1133 xsystem (ab); 1134 } 1135 1136 /* Test having the second system make an execution request. */ 1137 if (itest == 0 || itest == 5) 1138 { 1139 zfrom = "/usr/tmp/tstuu/from5"; 1140 if (fcall_uucico) 1141 zto = "/usr/spool/uucppublic/to5"; 1142 else 1143 zto = "/usr/tmp/tstuu/to5"; 1144 1145 (void) remove (zto); 1146 umake_file (zfrom, 11); 1147 1148 sprintf (ab, "%s test1!cat '<%s' '>%s'", zuux2, zfrom, zto); 1149 xsystem (ab); 1150 } 1151 1152 /* Test having the first system request a wildcard. */ 1153 if (itest == 0 || itest == 6) 1154 { 1155 const char *zfrom1, *zfrom2; 1156 1157 if (fcall_uucico) 1158 { 1159 zfrom = "/usr/spool/uucppublic/to6\\*"; 1160 zfrom1 = "/usr/spool/uucppublic/to6.1"; 1161 zfrom2 = "/usr/spool/uucppublic/to6.2"; 1162 } 1163 else 1164 { 1165 zfrom = "/usr/tmp/tstuu/spool2/to6\\*"; 1166 zfrom1 = "/usr/tmp/tstuu/spool2/to6.1"; 1167 zfrom2 = "/usr/tmp/tstuu/spool2/to6.2"; 1168 } 1169 1170 umake_file (zfrom1, 100); 1171 umake_file (zfrom2, 101); 1172 (void) remove ("/usr/tmp/tstuu/to6.1"); 1173 (void) remove ("/usr/tmp/tstuu/to6.2"); 1174 1175 sprintf (ab, "%s %s!%s /usr/tmp/tstuu", zuucp1, zsys, zfrom); 1176 xsystem (ab); 1177 } 1178 1179 /* Test having the second system request a wildcard. */ 1180 if (itest == 0 || itest == 7) 1181 { 1182 const char *zto1, *zto2; 1183 1184 if (fcall_uucico) 1185 { 1186 zto = "/usr/spool/uucppublic"; 1187 zto1 = "/usr/spool/uucppublic/to7.1"; 1188 zto2 = "/usr/spool/uucppublic/to7.2"; 1189 } 1190 else 1191 { 1192 zto = "/usr/tmp/tstuu"; 1193 zto1 = "/usr/tmp/tstuu/to7.1"; 1194 zto2 = "/usr/tmp/tstuu/to7.2"; 1195 } 1196 1197 umake_file ("/usr/tmp/tstuu/spool1/to7.1", 150); 1198 umake_file ("/usr/tmp/tstuu/spool1/to7.2", 155); 1199 (void) remove (zto1); 1200 (void) remove (zto2); 1201 1202 sprintf (ab, "%s test1!/usr/tmp/tstuu/spool1/to7.\\* %s", zuucp2, 1203 zto); 1204 xsystem (ab); 1205 } 1206 1207 /* Test an E command. This runs cat, discarding the output. */ 1208 if ((itest == 0 || itest == 8) && ! fcall_uucico) 1209 { 1210 umake_file ("/usr/tmp/tstuu/from8", 30); 1211 sprintf (ab, "%s - test2!cat < /usr/tmp/tstuu/from8", zuux1); 1212 xsystem (ab); 1213 } 1214} 1215 1216/* Try to make sure the file transfers were successful. */ 1217 1218static void 1219ucheck_test (itest, fcall_uucico) 1220 int itest; 1221 boolean fcall_uucico; 1222{ 1223 if (itest == 0 || itest == 1) 1224 { 1225 if (fcall_uucico) 1226 ucheck_file ("/usr/spool/uucppublic/to1", "test 1", 0); 1227 else 1228 ucheck_file ("/usr/tmp/tstuu/to1", "test 1", 0); 1229 } 1230 1231 if (itest == 0 || itest == 2) 1232 ucheck_file ("/usr/tmp/tstuu/to2", "test 2", 3); 1233 1234 if (itest == 0 || itest == 3) 1235 ucheck_file ("/usr/tmp/tstuu/to3", "test 3", 5); 1236 1237 if (itest == 0 || itest == 4) 1238 { 1239 if (fcall_uucico) 1240 ucheck_file ("/usr/spool/uucppublic/to4", "test 4", 7); 1241 else 1242 ucheck_file ("/usr/tmp/tstuu/to4", "test 4", 7); 1243 } 1244 1245 if (itest == 0 || itest == 6) 1246 { 1247 ucheck_file ("/usr/tmp/tstuu/to6.1", "test 6.1", 100); 1248 ucheck_file ("/usr/tmp/tstuu/to6.2", "test 6.2", 101); 1249 } 1250 1251 if (itest == 0 || itest == 7) 1252 { 1253 const char *zto1, *zto2; 1254 1255 if (fcall_uucico) 1256 { 1257 zto1 = "/usr/spool/uucppublic/to7.1"; 1258 zto2 = "/usr/spool/uucppublic/to7.2"; 1259 } 1260 else 1261 { 1262 zto1 = "/usr/tmp/tstuu/to7.1"; 1263 zto2 = "/usr/tmp/tstuu/to7.2"; 1264 } 1265 1266 ucheck_file (zto1, "test 7.1", 150); 1267 ucheck_file (zto2, "test 7.2", 155); 1268 } 1269} 1270 1271/* A debugging routine used when displaying buffers. */ 1272 1273static int 1274cpshow (z, ichar) 1275 char *z; 1276 int ichar; 1277{ 1278 if (isprint (BUCHAR (ichar)) && ichar != '\"') 1279 { 1280 *z = (char) ichar; 1281 return 1; 1282 } 1283 1284 *z++ = '\\'; 1285 1286 switch (ichar) 1287 { 1288 case '\n': 1289 *z = 'n'; 1290 return 2; 1291 case '\r': 1292 *z = 'r'; 1293 return 2; 1294 case '\"': 1295 *z = '\"'; 1296 return 2; 1297 default: 1298 sprintf (z, "%03o", (unsigned int)(ichar & 0xff)); 1299 return strlen (z) + 1; 1300 } 1301} 1302 1303/* Pick one of two file descriptors which is ready for reading, or 1304 return in five seconds. If the argument is ready for reading, 1305 leave it alone; otherwise set it to -1. */ 1306 1307static void 1308uchoose (po1, po2) 1309 int *po1; 1310 int *po2; 1311{ 1312#if HAVE_SELECT 1313 1314 int iread; 1315 struct timeval stime; 1316 1317 iread = (1 << *po1) | (1 << *po2); 1318 stime.tv_sec = 5; 1319 stime.tv_usec = 0; 1320 1321 if (select ((*po1 > *po2 ? *po1 : *po2) + 1, (pointer) &iread, 1322 (pointer) NULL, (pointer) NULL, &stime) < 0) 1323 { 1324 perror ("select"); 1325 uchild (SIGCHLD); 1326 } 1327 1328 if ((iread & (1 << *po1)) == 0) 1329 *po1 = -1; 1330 1331 if ((iread & (1 << *po2)) == 0) 1332 *po2 = -1; 1333 1334#else /* ! HAVE_SELECT */ 1335 1336#if HAVE_POLL 1337 1338 struct pollfd as[2]; 1339 1340 as[0].fd = *po1; 1341 as[0].events = POLLIN; 1342 as[1].fd = *po2; 1343 as[1].events = POLLIN; 1344 1345 if (poll (as, 2, 5 * 1000) < 0) 1346 { 1347 perror ("poll"); 1348 uchild (SIGCHLD); 1349 } 1350 1351 if ((as[0].revents & POLLIN) == 0) 1352 *po1 = -1; 1353 1354 if ((as[1].revents & POLLIN) == 0) 1355 *po2 = -1; 1356 1357#endif /* HAVE_POLL */ 1358#endif /* ! HAVE_SELECT */ 1359} 1360 1361/* Read some data from a file descriptor. This keeps reading until 1362 one of the reads gets no data. */ 1363 1364static long 1365cread (o, pqbuf) 1366 int o; 1367 struct sbuf **pqbuf; 1368{ 1369 long ctotal; 1370 1371 while (*pqbuf != NULL && (*pqbuf)->qnext != NULL) 1372 pqbuf = &(*pqbuf)->qnext; 1373 1374 ctotal = 0; 1375 1376 while (TRUE) 1377 { 1378 int cgot; 1379 1380 if (*pqbuf != NULL 1381 && (size_t) (*pqbuf)->cend >= sizeof (*pqbuf)->ab) 1382 pqbuf = &(*pqbuf)->qnext; 1383 1384 if (*pqbuf == NULL) 1385 { 1386 *pqbuf = (struct sbuf *) malloc (sizeof (struct sbuf)); 1387 if (*pqbuf == NULL) 1388 { 1389 fprintf (stderr, "Out of memory\n"); 1390 uchild (SIGCHLD); 1391 } 1392 (*pqbuf)->qnext = NULL; 1393 (*pqbuf)->cstart = 0; 1394 (*pqbuf)->cend = 0; 1395 } 1396 1397 cgot = read (o, (*pqbuf)->ab + (*pqbuf)->cend, 1398 (sizeof (*pqbuf)->ab) - (*pqbuf)->cend); 1399 if (cgot < 0) 1400 { 1401 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA) 1402 cgot = 0; 1403 else 1404 { 1405 perror ("read"); 1406 uchild (SIGCHLD); 1407 } 1408 } 1409 1410 if (cgot == 0) 1411 return ctotal; 1412 1413 ctotal += cgot; 1414 1415 if (zDebug != NULL) 1416 { 1417 char abshow[325]; 1418 char *zfrom; 1419 char *zshow; 1420 int i; 1421 1422 zfrom = (*pqbuf)->ab + (*pqbuf)->cend; 1423 zshow = abshow; 1424 for (i = 0; i < cgot && i < 80; i++, zfrom++) 1425 zshow += cpshow (zshow, *zfrom); 1426 if (i < cgot) 1427 { 1428 *zshow++ = '.'; 1429 *zshow++ = '.'; 1430 *zshow++ = '.'; 1431 } 1432 *zshow = '\0'; 1433 fprintf (stderr, "Read from %d: %d \"%s\"\n", o, cgot, abshow); 1434 fflush (stderr); 1435 } 1436 1437 if (iPercent > 0) 1438 { 1439 int i; 1440 int c; 1441 1442 c = 0; 1443 for (i = 0; i < cgot; i++) 1444 { 1445 if (rand () % 1000 < iPercent) 1446 { 1447 ++(*pqbuf)->ab[(*pqbuf)->cend + i]; 1448 ++c; 1449 } 1450 } 1451 if (zDebug != NULL && c > 0) 1452 fprintf (stderr, "Clobbered %d bytes\n", c); 1453 } 1454 1455 (*pqbuf)->cend += cgot; 1456 1457 if (ctotal > 256) 1458 return ctotal; 1459 } 1460} 1461 1462/* Write data to a file descriptor until one of the writes gets no 1463 data. */ 1464 1465static boolean 1466fsend (o, oslave, pqbuf) 1467 int o; 1468 int oslave; 1469 struct sbuf **pqbuf; 1470{ 1471 long ctotal; 1472 1473 ctotal = 0; 1474 while (*pqbuf != NULL) 1475 { 1476 int cwrite, cwrote; 1477 1478 if ((*pqbuf)->cstart >= (*pqbuf)->cend) 1479 { 1480 struct sbuf *qfree; 1481 1482 qfree = *pqbuf; 1483 *pqbuf = (*pqbuf)->qnext; 1484 free ((pointer) qfree); 1485 continue; 1486 } 1487 1488#ifdef FIONREAD 1489 { 1490 long cunread; 1491 1492 if (ioctl (oslave, FIONREAD, &cunread) < 0) 1493 { 1494 perror ("FIONREAD"); 1495 uchild (SIGCHLD); 1496 } 1497 if (zDebug != NULL) 1498 fprintf (stderr, "%ld unread\n", cunread); 1499 cwrite = 256 - cunread; 1500 if (cwrite <= 0) 1501 break; 1502 } 1503#else /* ! FIONREAD */ 1504 if (! fwritable (o)) 1505 break; 1506 cwrite = 1; 1507#endif /* ! FIONREAD */ 1508 1509 if (cwrite > (*pqbuf)->cend - (*pqbuf)->cstart) 1510 cwrite = (*pqbuf)->cend - (*pqbuf)->cstart; 1511 1512 cwrote = write (o, (*pqbuf)->ab + (*pqbuf)->cstart, cwrite); 1513 if (cwrote < 0) 1514 { 1515 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA) 1516 cwrote = 0; 1517 else 1518 { 1519 perror ("write"); 1520 uchild (SIGCHLD); 1521 } 1522 } 1523 1524 if (cwrote == 0) 1525 break; 1526 1527 ctotal += cwrote; 1528 (*pqbuf)->cstart += cwrote; 1529 } 1530 1531 if (zDebug != NULL && ctotal > 0) 1532 fprintf (stderr, "Wrote %ld to %d\n", ctotal, o); 1533 1534 return ctotal > 0; 1535} 1536 1537/* Check whether a file descriptor can be written to. */ 1538 1539static boolean 1540fwritable (o) 1541 int o; 1542{ 1543#if HAVE_SELECT 1544 1545 int iwrite; 1546 struct timeval stime; 1547 int cfds; 1548 1549 iwrite = 1 << o; 1550 1551 stime.tv_sec = 0; 1552 stime.tv_usec = 0; 1553 1554 cfds = select (o + 1, (pointer) NULL, (pointer) &iwrite, 1555 (pointer) NULL, &stime); 1556 if (cfds < 0) 1557 { 1558 perror ("select"); 1559 uchild (SIGCHLD); 1560 } 1561 1562 return cfds > 0; 1563 1564#else /* ! HAVE_SELECT */ 1565 1566#if HAVE_POLL 1567 1568 struct pollfd s; 1569 int cfds; 1570 1571 s.fd = o; 1572 s.events = POLLOUT; 1573 1574 cfds = poll (&s, 1, 0); 1575 if (cfds < 0) 1576 { 1577 perror ("poll"); 1578 uchild (SIGCHLD); 1579 } 1580 1581 return cfds > 0; 1582 1583#endif /* HAVE_POLL */ 1584#endif /* ! HAVE_SELECT */ 1585} 1586 1587/* A version of the system command that checks for errors. */ 1588 1589static void 1590xsystem (zcmd) 1591 const char *zcmd; 1592{ 1593 int istat; 1594 1595 istat = system ((char *) zcmd); 1596 if (istat != 0) 1597 { 1598 fprintf (stderr, "Command failed with status %d\n", istat); 1599 fprintf (stderr, "%s\n", zcmd); 1600 exit (EXIT_FAILURE); 1601 } 1602} 1603