1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1998 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include "uucp.h" 34 35 #define SHORTBUF 64 36 37 #define NOSYSPART 0 38 39 #define GENSEND(f, a, b, c) {\ 40 ASSERT(fprintf(f, "S %s %s %s -%s %s 0666 %s %s\n", a, b, User, _Statop?"o":"", c, User, _Sfile) >= 0, Ct_WRITE, "", errno);\ 41 } 42 #define GENRCV(f, a, b) {\ 43 char tbuf[SHORTBUF]; \ 44 gename (DATAPRE, xsys, 'Z', tbuf); \ 45 ASSERT(fprintf(f, "R %s %s %s - %s 0666 %s %s\n", a, b, User, _Sfile, User, tbuf) \ 46 >= 0, Ct_WRITE, "", errno);\ 47 } 48 49 #define STRNCPY(str1, str2) { \ 50 (void) strncpy(str1, str2, (sizeof(str1) - 1)); \ 51 str1[sizeof(str1) - 1] = '\0'; \ 52 } 53 #define STRNCAT(str1, str2) { \ 54 (void) strncat(str1, str2, \ 55 (sizeof(str1) - 1 - strlen(str1))); \ 56 } 57 #define APPCMD(p) {STRNCAT(cmd, p); STRNCAT(cmd, " ");} 58 59 static char _Sfile[MAXFULLNAME]; 60 static int _Statop; 61 char Sgrade[NAMESIZE]; 62 void cleanup(); 63 static void usage(); 64 65 /* 66 * uux 67 */ 68 main(argc, argv, envp) 69 char *argv[]; 70 char *envp[]; 71 { 72 char *jid(); 73 FILE *fprx = NULL, *fpc = NULL, *fpd = NULL, *fp = NULL; 74 static void onintr(); 75 int cfileUsed = 0; /* >0 if commands put in C. file flag */ 76 int cflag = 0; /* if > 0 make local copy of files to be sent */ 77 int nflag = 0; /* if != 0, do not request error notification */ 78 int zflag = 0; /* if != 0, request success notification */ 79 int pipein = 0; 80 int startjob = 1; 81 short jflag = 0; /* -j flag output Jobid */ 82 int bringback = 0; /* return stdin to invoker on error */ 83 int ret, i; 84 char *getprm(); 85 char redir = '\0'; /* X_STDIN, X_STDOUT, X_STDERR as approprite */ 86 char command = TRUE; 87 char cfile[NAMESIZE]; /* send commands for files from here */ 88 char dfile[NAMESIZE]; /* used for all data files from here */ 89 char rxfile[NAMESIZE]; /* file for X_ commands */ 90 char tfile[NAMESIZE]; /* temporary file name */ 91 char t2file[NAMESIZE]; /* temporary file name */ 92 char buf[BUFSIZ]; 93 char inargs[BUFSIZ]; 94 char cmd[BUFSIZ]; 95 char *ap; 96 char prm[BUFSIZ]; 97 char syspart[MAXFULLNAME], rest[BUFSIZ]; 98 char xsys[MAXFULLNAME]; 99 char *fopt = NULL; 100 char *retaddr = NULL; 101 struct stat stbuf; 102 103 /* Set locale environment variables local definitions */ 104 (void) setlocale(LC_ALL, ""); 105 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 106 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 107 #endif 108 (void) textdomain(TEXT_DOMAIN); 109 110 /* we want this to run as uucp, even if the kernel doesn't */ 111 Uid = getuid(); 112 Euid = geteuid(); /* this should be UUCPUID */ 113 if (Uid == 0) 114 setuid(UUCPUID); 115 116 /* init environment for fork-exec */ 117 Env = envp; 118 119 /* choose LOGFILE */ 120 STRNCPY(Logfile, LOGUUX); 121 122 /* 123 * determine local system name 124 */ 125 (void) strcpy(Progname, "uux"); 126 Pchar = 'X'; 127 (void) signal(SIGILL, onintr); 128 (void) signal(SIGTRAP, onintr); 129 (void) signal(SIGIOT, onintr); 130 (void) signal(SIGEMT, onintr); 131 (void) signal(SIGFPE, onintr); 132 (void) signal(SIGBUS, onintr); 133 (void) signal(SIGSEGV, onintr); 134 (void) signal(SIGSYS, onintr); 135 (void) signal(SIGTERM, SIG_IGN); 136 uucpname(Myname); 137 Ofn = 1; 138 Ifn = 0; 139 *_Sfile = '\0'; 140 141 /* 142 * determine id of user starting remote 143 * execution 144 */ 145 guinfo(Uid, User); 146 STRNCPY(Loginuser,User); 147 148 *Sgrade = NULLCHAR; 149 150 /* 151 * this is a check to see if we are using the administrator 152 * defined service grade. The GRADES file will determine if 153 * we are. If so then setup the default grade variables. 154 */ 155 156 if (eaccess(GRADES, 04) != -1) { 157 Grade = 'A'; 158 Sgrades = TRUE; 159 STRNCPY(Sgrade, "default"); 160 } 161 162 /* 163 * create/append command log 164 */ 165 commandlog(argc,argv); 166 167 /* 168 * since getopt() can't handle the pipe input option '-'; 169 * change it to "-p" 170 */ 171 for (i=1; i<argc && *argv[i] == '-'; i++) 172 if (EQUALS(argv[i], "-")) 173 argv[i] = "-p"; 174 175 while ((i = getopt(argc, argv, "a:bcCjg:nprs:x:z")) != EOF) { 176 switch(i){ 177 178 /* 179 * use this name in the U line 180 */ 181 case 'a': 182 retaddr = optarg; 183 break; 184 185 /* 186 * if return code non-zero, return command's input 187 */ 188 case 'b': 189 bringback = 1; 190 break; 191 192 /* do not make local copies of files to be sent (default) */ 193 case 'c': 194 cflag = 0; 195 break; 196 197 /* make local copies of files to be sent */ 198 case 'C': 199 cflag = 1; 200 break; 201 202 /* 203 * set priority of request 204 */ 205 case 'g': 206 if (!Sgrades) { 207 if (strlen(optarg) < (size_t) 2 && isalnum(*optarg)) 208 Grade = *optarg; 209 else { 210 (void) fprintf(stderr, gettext("No" 211 " administrator defined service" 212 " grades available on this" 213 " machine.\n")); 214 (void) fprintf(stderr, gettext("UUCP" 215 " service grades range from" 216 " [A-Z][a-z] only.\n")); 217 cleanup(-1); 218 } 219 } 220 else { 221 STRNCPY(Sgrade, optarg); 222 if (vergrd(Sgrade) != SUCCESS) 223 cleanup(FAIL); 224 } 225 break; 226 227 228 case 'j': /* job id */ 229 jflag = 1; 230 break; 231 232 233 /* 234 * do not send failure notification to user 235 */ 236 case 'n': 237 nflag++; 238 break; 239 240 /* 241 * send success notification to user 242 */ 243 case 'z': 244 zflag++; 245 break; 246 247 /* 248 * -p or - option specifies input from pipe 249 */ 250 case 'p': 251 pipein = 1; 252 break; 253 254 /* 255 * do not start transfer 256 */ 257 case 'r': 258 startjob = 0; 259 break; 260 261 case 's': 262 fopt = optarg; 263 _Statop++; 264 break; 265 266 /* 267 * debugging level 268 */ 269 case 'x': 270 Debug = atoi(optarg); 271 if (Debug <= 0) 272 Debug = 1; 273 break; 274 275 default: 276 usage(); 277 } 278 } 279 280 DEBUG(4, "\n\n** %s **\n", "START"); 281 282 if( optind >= argc ) 283 usage(); 284 285 /* 286 * copy arguments into a buffer for later 287 * processing 288 */ 289 inargs[0] = '\0'; 290 for (; optind < argc; optind++) { 291 DEBUG(4, "arg - %s:", argv[optind]); 292 STRNCAT(inargs, " "); 293 STRNCAT(inargs, argv[optind]); 294 } 295 296 /* 297 * get working directory and change 298 * to spool directory 299 */ 300 DEBUG(4, "arg - %s\n", inargs); 301 gwd(Wrkdir); 302 if(fopt){ 303 if(*fopt != '/') { 304 (void) snprintf(_Sfile, (sizeof(_Sfile) - 1), 305 "%s/%s", Wrkdir, fopt); 306 _Sfile[sizeof(_Sfile) - 1] = '\0'; 307 } 308 else { 309 (void) snprintf(_Sfile, (sizeof(_Sfile) - 1), 310 "%s", fopt); 311 _Sfile[sizeof(_Sfile) - 1] = '\0'; 312 } 313 } 314 else 315 strcpy(_Sfile, "dummy"); 316 317 if (chdir(WORKSPACE) != 0) { 318 (void) fprintf(stderr, 319 gettext("No spool directory - %s - get help\n"), WORKSPACE); 320 cleanup(EX_OSERR); 321 } 322 /* 323 * find remote system name 324 * remote name is first to know that 325 * is not > or < 326 */ 327 ap = inargs; 328 xsys[0] = '\0'; 329 while ((ap = getprm(ap, (char *)NULL, prm)) != NULL) { 330 if (prm[0] == '>' || prm[0] == '<') { 331 ap = getprm(ap, (char *)NULL, prm); 332 continue; 333 } 334 335 /* 336 * split name into system name 337 * and command name 338 */ 339 (void) split(prm, xsys, CNULL, rest); 340 break; 341 } 342 if (xsys[0] == '\0') 343 STRNCPY(xsys, Myname); 344 STRNCPY(Rmtname, xsys); 345 DEBUG(4, "xsys %s\n", xsys); 346 347 /* get real Myname - it depends on who I'm calling--Rmtname */ 348 (void) mchFind(Rmtname); 349 myName(Myname); 350 351 /* 352 * check to see if system name is valid 353 */ 354 if (versys(xsys) != 0) { 355 /* 356 * bad system name 357 */ 358 fprintf(stderr, gettext("bad system name: %s\n"), xsys); 359 if (fprx != NULL) 360 (void) fclose(fprx); 361 if (fpc != NULL) 362 (void) fclose(fpc); 363 cleanup(EX_NOHOST); 364 } 365 366 DEBUG(6, "User %s\n", User); 367 if (retaddr == NULL) 368 retaddr = User; 369 370 /* 371 * initialize command buffer 372 */ 373 *cmd = '\0'; 374 375 /* 376 * generate JCL files to work from 377 */ 378 379 /* 380 * fpc is the C. file for the local site. 381 * collect commands into cfile. 382 * commit if not empty (at end). 383 * 384 * the appropriate C. file. 385 */ 386 gename(CMDPRE, xsys, Grade, cfile); 387 DEBUG(9, "cfile = %s\n", cfile); 388 ASSERT(access(cfile, 0) != 0, Fl_EXISTS, cfile, errno); 389 fpc = fdopen(ret = creat(cfile, CFILEMODE), "w"); 390 ASSERT(ret >= 0 && fpc != NULL, Ct_OPEN, cfile, errno); 391 setbuf(fpc, CNULL); 392 393 /* set Jobid -- C.jobid */ 394 STRNCPY(Jobid, BASENAME(cfile, '.')); 395 396 /* 397 * rxfile is the X. file for the job, fprx is its stream ptr. 398 * if the command is to be executed locally, rxfile becomes 399 * a local X. file, otherwise we send it as a D. file to the 400 * remote site. 401 */ 402 403 gename(DATAPRE, xsys, 'X', rxfile); 404 DEBUG(9, "rxfile = %s\n", rxfile); 405 ASSERT(access(rxfile, 0) != 0, Fl_EXISTS, rxfile, errno); 406 fprx = fdopen(ret = creat(rxfile, DFILEMODE), "w"); 407 ASSERT(ret >= 0 && fprx != NULL, Ct_WRITE, rxfile, errno); 408 setbuf(fprx, CNULL); 409 clearerr(fprx); 410 411 (void) fprintf(fprx,"%c %s %s\n", X_USER, User, Myname); 412 if (zflag) { 413 (void) fprintf(fprx, "%c return status on success\n", 414 X_COMMENT); 415 (void) fprintf(fprx,"%c\n", X_SENDZERO); 416 } 417 418 if (nflag) { 419 (void) fprintf(fprx, "%c don't return status on failure\n", 420 X_COMMENT); 421 (void) fprintf(fprx,"%c\n", X_SENDNOTHING); 422 } else { 423 (void) fprintf(fprx, "%c return status on failure\n", 424 X_COMMENT); 425 fprintf(fprx,"%c\n", X_NONZERO); 426 } 427 428 if (bringback) { 429 (void) fprintf(fprx, "%c return input on abnormal exit\n", 430 X_COMMENT); 431 (void) fprintf(fprx,"%c\n", X_BRINGBACK); 432 } 433 434 if (_Statop) 435 (void) fprintf(fprx,"%c %s\n", X_MAILF, _Sfile); 436 437 if (retaddr != NULL) { 438 (void) fprintf(fprx, "%c return address for status or input return\n", 439 X_COMMENT); 440 (void) fprintf(fprx,"%c %s\n", X_RETADDR, retaddr); 441 } 442 443 (void) fprintf(fprx, "%c job id for status reporting\n", X_COMMENT); 444 (void) fprintf(fprx,"%c %s\n", X_JOBID, Jobid); 445 446 /* 447 * create a JCL file to spool pipe input into 448 */ 449 if (pipein) { 450 /* 451 * fpd is the D. file into which we now read 452 * input from stdin 453 */ 454 455 gename(DATAPRE, Myname, 'B', dfile); 456 457 ASSERT(access(dfile, 0) != 0, Fl_EXISTS, dfile, errno); 458 fpd = fdopen(ret = creat(dfile, DFILEMODE), "w"); 459 ASSERT(ret >= 0 && fpd != NULL, Ct_OPEN, dfile, errno); 460 461 /* 462 * read pipe to EOF 463 */ 464 while (!feof(stdin)) { 465 ret = fread(buf, 1, BUFSIZ, stdin); 466 ASSERT(fwrite(buf, 1, ret, fpd) == ret, Ct_WRITE, 467 dfile, errno); 468 } 469 ASSERT(fflush(fpd) != EOF && ferror(fpd) == 0, Ct_WRITE, dfile, errno); 470 (void) fclose(fpd); 471 472 /* 473 * if command is to be executed on remote 474 * create extra JCL 475 */ 476 if (!EQUALSN(Myname, xsys, MAXBASENAME)) { 477 GENSEND(fpc, dfile, dfile, dfile); 478 } 479 480 /* 481 * create file for X_ commands 482 */ 483 (void) fprintf(fprx, "%c %s\n", X_RQDFILE, dfile); 484 (void) fprintf(fprx, "%c %s\n", X_STDIN, dfile); 485 486 if (EQUALS(Myname, xsys)) 487 wfcommit(dfile, dfile, xsys); 488 489 } 490 /* 491 * parse command 492 */ 493 ap = inargs; 494 while ((ap = getprm(ap, (char *)NULL, prm)) != NULL) { 495 DEBUG(4, "prm - %s\n", prm); 496 497 /* 498 * redirection of I/O 499 */ 500 if ( prm[0] == '<' ) { 501 if (prm[1] == '<') { 502 fprintf(stderr, 503 gettext("'<<' may not be used in command\n")); 504 cleanup(EX_USAGE); 505 } 506 redir = X_STDIN; 507 continue; 508 } 509 if ( prm[0] == '>' ) { 510 if (prm[1] == '>') { 511 fprintf(stderr, 512 gettext("'>>' may not be used in command\n")); 513 cleanup(EX_USAGE); 514 } 515 if (prm[1] == '|') { 516 fprintf(stderr, 517 gettext("'>|' may not be used in command\n")); 518 cleanup(EX_USAGE); 519 } 520 if (prm[1] == '&') { 521 fprintf(stderr, 522 gettext("'>&' may not be used in command\n")); 523 cleanup(EX_USAGE); 524 } 525 redir = X_STDOUT; 526 continue; 527 } 528 if ( EQUALS(prm, "2>") ) { 529 redir = X_STDERR; 530 continue; 531 } 532 533 /* 534 * some terminator 535 */ 536 if ( prm[0] == '|' || prm[0] == '^' 537 || prm[0] == '&' || prm[0] == ';') { 538 if (*cmd != '\0') /* not 1st thing on line */ 539 APPCMD(prm); 540 command = TRUE; 541 continue; 542 } 543 544 /* 545 * process command or file or option 546 * break out system and file name and 547 * use default if necessary 548 */ 549 ret = split(prm, syspart, CNULL, rest); 550 DEBUG(4, "syspart -> %s, ", syspart); 551 DEBUG(4, "rest -> %s, ", rest); 552 DEBUG(4, "ret -> %d\n", ret); 553 554 if (command && redir == '\0') { 555 /* 556 * command 557 */ 558 APPCMD(rest); 559 command = FALSE; 560 continue; 561 } 562 563 if (syspart[0] == '\0') { 564 STRNCPY(syspart, Myname); 565 DEBUG(6, "syspart -> %s\n", syspart); 566 } else if (versys(syspart) != 0) { 567 /* 568 * bad system name 569 */ 570 fprintf(stderr, 571 gettext("bad system name: %s\n"), syspart); 572 if (fprx != NULL) 573 (void) fclose(fprx); 574 if (fpc != NULL) 575 (void) fclose(fpc); 576 cleanup(EX_NOHOST); 577 } 578 579 /* 580 * process file or option 581 */ 582 583 /* 584 * process file argument 585 * expand filename and create JCL card for 586 * redirected output 587 * e.g., X file sys 588 */ 589 if ((redir == X_STDOUT) || (redir == X_STDERR)) { 590 if (rest[0] != '~') 591 if (ckexpf(rest)) 592 cleanup(EX_OSERR); 593 ASSERT(fprintf(fprx, "%c %s %s\n", redir, rest, 594 syspart) >= 0, Ct_WRITE, rxfile, errno); 595 redir = '\0'; 596 continue; 597 } 598 599 /* 600 * if no system specified, then being 601 * processed locally 602 */ 603 if (ret == NOSYSPART && redir == '\0') { 604 605 /* 606 * option 607 */ 608 APPCMD(rest); 609 continue; 610 } 611 612 613 /* local xeqn + local file (!x !f) */ 614 if ((EQUALSN(xsys, Myname, MAXBASENAME)) 615 && (EQUALSN(xsys, syspart, MAXBASENAME))) { 616 /* 617 * create JCL card 618 */ 619 if (ckexpf(rest)) 620 cleanup(EX_OSERR); 621 /* 622 * JCL card for local input 623 * e.g., I file 624 */ 625 if (redir == X_STDIN) { 626 (void) fprintf(fprx, "%c %s\n", X_STDIN, rest); 627 } else 628 APPCMD(rest); 629 ASSERT(fprx != NULL, Ct_WRITE, rxfile, errno); 630 redir = '\0'; 631 continue; 632 } 633 634 /* remote xeqn + local file (sys!x !f) */ 635 if (EQUALSN(syspart, Myname, MAXBASENAME)) { 636 /* 637 * check access to local file 638 * if cflag is set, copy to spool directory 639 * otherwise, just mention it in the X. file 640 */ 641 if (ckexpf(rest)) 642 cleanup(EX_OSERR); 643 DEBUG(4, "rest %s\n", rest); 644 645 /* see if I can read this file as read uid, gid */ 646 if (uidstat(rest, &stbuf) != 0) { 647 (void) fprintf(stderr, 648 gettext("can't get file status %s\n"), rest); 649 cleanup(EX_OSERR); 650 } 651 /* XXX - doesn't check group list */ 652 if ( !(stbuf.st_mode & ANYREAD) 653 && !(stbuf.st_uid == Uid && stbuf.st_mode & 0400) 654 && !(stbuf.st_gid ==getgid() && stbuf.st_mode & 0040) 655 ) { 656 fprintf(stderr, 657 gettext("permission denied %s\n"), rest); 658 cleanup(EX_CANTCREAT); 659 } 660 661 /* D. file for sending local file */ 662 gename(DATAPRE, xsys, 'A', dfile); 663 664 if (cflag || !(stbuf.st_mode & ANYREAD)) { 665 /* make local copy */ 666 if (uidxcp(rest, dfile) != 0) { 667 fprintf(stderr, 668 gettext("can't copy %s\n"), rest); 669 cleanup(EX_CANTCREAT); 670 } 671 (void) chmod(dfile, DFILEMODE); 672 /* generate 'send' entry in command file */ 673 GENSEND(fpc, rest, dfile, dfile); 674 } else /* don't make local copy */ 675 GENSEND(fpc, rest, dfile, dfile); 676 677 /* 678 * JCL cards for redirected input in X. file, 679 * e.g. 680 * I D.xxx 681 * F D.xxx 682 */ 683 if (redir == X_STDIN) { 684 /* 685 * don't bother making a X_RQDFILE line that 686 * renames stdin on the remote side, since the 687 * remote command can't know its name anyway 688 */ 689 (void) fprintf(fprx, "%c %s\n", X_STDIN, dfile); 690 (void) fprintf(fprx, "%c %s\n", X_RQDFILE, dfile); 691 } else { 692 APPCMD(BASENAME(rest, '/'));; 693 /* 694 * generate X. JCL card that specifies 695 * F file 696 */ 697 (void) fprintf(fprx, "%c %s %s\n", X_RQDFILE, 698 dfile, BASENAME(rest, '/')); 699 } 700 redir = '\0'; 701 702 continue; 703 } 704 705 /* local xeqn + remote file (!x sys!f ) */ 706 if (EQUALS(Myname, xsys)) { 707 /* 708 * expand receive file name 709 */ 710 if (ckexpf(rest)) 711 cleanup(EX_OSERR); 712 /* 713 * strategy: 714 * request rest from syspart. when it arrives, 715 * we can run the command. 716 * 717 * tfile is command file for receive from remote. 718 * we defer commiting until later so 719 * that only one C. file is created per site. 720 * 721 * dfile is name of data file to receive into; 722 * we don't use it, just name it. 723 * 724 * once the data file arrives from syspart. 725 * arrange so that in the X. file (fprx), rest is 726 * required and named appropriately. this 727 * necessitates local access to SPOOL/syspart, which 728 * is handled by a hook in uuxqt that allows files 729 * in SPOOL/syspart to be renamed on the F line. 730 * 731 * pictorially: 732 * 733 * ===== syspart/C.syspart.... ===== (tfile) 734 * R rest D.syspart... (dfile) 735 * 736 * 737 * ===== local/X.local... ===== (fprx) 738 * F SPOOL/syspart/D.syspart... rest (dfile) 739 * 740 * 741 */ 742 if (gtcfile(tfile, syspart) != SUCCESS) { 743 gename(CMDPRE, syspart, 'R', tfile); 744 745 ASSERT(access(tfile, 0) != 0, 746 Fl_EXISTS, tfile, errno); 747 svcfile(tfile, syspart, Sgrade); 748 (void) close(creat(tfile, CFILEMODE)); 749 } 750 fp = fopen(tfile, "a"); 751 ASSERT(fp != NULL, Ct_OPEN, tfile, errno); 752 setbuf(fp, CNULL); 753 gename(DATAPRE, syspart, 'R', dfile); 754 755 /* prepare JCL card to receive file */ 756 GENRCV(fp, rest, dfile); 757 ASSERT(fflush(fp) != EOF && ferror(fp) == 0, Ct_WRITE, dfile, errno); 758 (void) fclose(fp); 759 if (rest[0] != '~') 760 if (ckexpf(rest)) 761 cleanup(EX_OSERR); 762 763 /* 764 * generate receive entries 765 */ 766 if (redir == X_STDIN) { 767 (void) fprintf(fprx, 768 "%c %s/%s/%s\n", X_RQDFILE, Spool, 769 syspart, dfile); 770 (void) fprintf(fprx, "%c %s\n", X_STDIN, dfile); 771 } else { 772 (void) fprintf(fprx, "%c %s/%s/%s %s\n", 773 X_RQDFILE, Spool, syspart, dfile, 774 BASENAME(rest, '/')); 775 APPCMD(BASENAME(rest, '/')); 776 } 777 778 redir = '\0'; 779 continue; 780 } 781 782 /* remote xeqn/file, different remotes (xsys!cmd syspart!rest) */ 783 if (!EQUALS(syspart, xsys)) { 784 /* 785 * strategy: 786 * request rest from syspart. 787 * 788 * set up a local X. file that will send rest to xsys, 789 * once it arrives from syspart. 790 * 791 * arrange so that in the xsys D. file (fated to become 792 * an X. file on xsys), rest is required and named. 793 * 794 * pictorially: 795 * 796 * ===== syspart/C.syspart.... ===== (tfile) 797 * R rest D.syspart... (dfile) 798 * 799 * 800 * ===== local/X.local... ===== (t2file) 801 * F Spool/syspart/D.syspart... rest (dfile) 802 * C uucp -C rest D.syspart... (dfile) 803 * 804 * ===== xsys/D.xsysG.... (fprx) 805 * F D.syspart... rest (dfile) 806 * or, in the case of redir == '<' 807 * F D.syspart... (dfile) 808 * I D.syspart... (dfile) 809 * 810 * while we do push rest around a bunch, 811 * we use the protection scheme to good effect. 812 * 813 * we must rely on uucp's treatment of requests 814 * from XQTDIR to get the data file to the right 815 * place ultimately. 816 */ 817 818 /* build (or append to) C.syspart... */ 819 if (gtcfile(tfile, syspart) != SUCCESS) { 820 gename(CMDPRE, syspart, 'R', tfile); 821 822 ASSERT(access(tfile, 0) != 0, 823 Fl_EXISTS, tfile, errno); 824 svcfile(tfile, syspart, Sgrade); 825 (void) close(creat(tfile, CFILEMODE)); 826 } 827 fp = fopen(tfile, "a"); 828 ASSERT(fp != NULL, Ct_OPEN, tfile, errno); 829 setbuf(fp, CNULL); 830 gename(DATAPRE, syspart, 'R', dfile); 831 GENRCV(fp, rest, dfile); 832 ASSERT(fflush(fp) != EOF && ferror(fp) == 0, Ct_WRITE, dfile, errno); 833 (void) fclose(fp); 834 835 /* build local/X.localG... */ 836 /* name might collide with rxfile; no real danger */ 837 gename(XQTPRE, Myname, Grade, t2file); 838 ASSERT(access(t2file, 0)!=0, Fl_EXISTS, t2file, errno); 839 (void) close(creat(t2file, CFILEMODE)); 840 fp = fopen(t2file, "w"); 841 ASSERT(fp != NULL, Ct_OPEN, t2file, errno); 842 setbuf(fp, CNULL); 843 (void) fprintf(fp, "%c third party request, job id\n", 844 X_COMMENT); 845 (void) fprintf(fp, "%c %s\n", X_JOBID, Jobid); 846 (void) fprintf(fp, "%c %s/%s/%s %s\n", X_RQDFILE, 847 Spool, syspart, dfile, BASENAME(rest, '/')); 848 (void) fprintf(fp, "%c uucp -C %s %s!%s\n", 849 X_CMD, BASENAME(rest, '/'), xsys, dfile); 850 ASSERT(fflush(fp) != EOF && ferror(fp) == 0, Ct_WRITE, t2file, errno); 851 (void) fclose(fp); 852 853 /* put t2file where uuxqt can get at it */ 854 wfcommit(t2file, t2file, Myname); 855 856 /* generate xsys/X.sysG... cards */ 857 if (redir == X_STDIN) { 858 (void) fprintf(fprx, "%c %s\n", 859 X_RQDFILE, dfile); 860 (void) fprintf(fprx, "%c %s\n", X_STDIN, dfile); 861 } else { 862 (void) fprintf(fprx, "%c %s %s\n", X_RQDFILE, 863 dfile, BASENAME(rest, '/')); 864 APPCMD(BASENAME(rest, '/')); 865 } 866 redir = '\0'; 867 continue; 868 } 869 870 /* remote xeqn + remote file, same remote (sys!x sys!f) */ 871 if (rest[0] != '~') /* expand '~' on remote */ 872 if (ckexpf(rest)) 873 cleanup(EX_OSERR); 874 if (redir == X_STDIN) { 875 (void) fprintf(fprx, "%c %s\n", X_STDIN, rest); 876 } 877 else 878 APPCMD(rest); 879 redir = '\0'; 880 continue; 881 882 } 883 884 /* 885 * place command to be executed in JCL file 886 */ 887 (void) fprintf(fprx, "%c %s\n", X_CMD, cmd); 888 ASSERT(fflush(fprx) != EOF && ferror(fprx) == 0, Ct_WRITE, rxfile, errno); 889 (void) fclose(fprx); /* rxfile is ready for commit */ 890 logent(cmd, "QUEUED"); 891 892 gename(XQTPRE, Myname, Grade, tfile); 893 if (EQUALS(xsys, Myname)) { 894 /* local xeqn -- use X_ file here */ 895 /* this use of the X_ file can not collide with the earlier one */ 896 wfcommit(rxfile, tfile, xsys); 897 898 /* 899 * see if -r option requested JCL to be queued only 900 */ 901 if (startjob) 902 xuuxqt(Myname); 903 } else { 904 /* remote xeqn -- send rxfile to remote */ 905 /* put it in a place where cico can get at it */ 906 /* X_ file name might collide with an earlier use, */ 907 /* but that one lives locally, while this one gets shipped */ 908 909 GENSEND(fpc, rxfile, tfile, rxfile); 910 } 911 912 cfileUsed = (ftell(fpc) != 0L); /* was cfile used? */ 913 ASSERT(fflush(fpc) != EOF && ferror(fpc) == 0, Ct_WRITE, cfile, errno); 914 (void) fclose(fpc); 915 916 /* commit C. files for remote receive */ 917 918 commitall(); 919 920 /* 921 * has any command been placed in command JCL file 922 */ 923 if (cfileUsed) { 924 925 svcfile(cfile, xsys, Sgrade); 926 commitall(); 927 928 /* 929 * see if -r option requested JCL to be queued only 930 */ 931 if (startjob) 932 xuucico(xsys); 933 } else 934 unlink(cfile); 935 936 if (jflag) { /* print Jobid */ 937 STRNCPY(Jobid, jid()); 938 printf("%s\n", Jobid); 939 } 940 941 cleanup(0); 942 /* NOTREACHED */ 943 } 944 945 946 /* 947 * cleanup and unlink if error 948 * code -> exit code 949 * return: 950 * none 951 */ 952 void 953 cleanup(code) 954 register int code; 955 { 956 static int first = 1; 957 958 /* prevent recursion on errors */ 959 if (first) { 960 first = 0; 961 rmlock(CNULL); 962 if (code) { 963 fprintf(stderr, gettext("uux failed ( %d )\n"), code); 964 wfabort(); 965 } 966 } 967 DEBUG(1, "exit code %d\n", code); 968 if (code < 0) 969 exit(-code); 970 else 971 exit(code); 972 } 973 974 /* 975 * catch signal then cleanup and exit 976 */ 977 static void 978 onintr(inter) 979 register int inter; 980 { 981 char str[30]; 982 (void) signal(inter, SIG_IGN); 983 (void) sprintf(str, "XSIGNAL %d", inter); 984 logent(str, "XCAUGHT"); 985 cleanup(EX_TEMPFAIL); 986 } 987 988 989 static void 990 usage() 991 { 992 (void) fprintf(stderr, gettext("Usage: %s [-bcCjnprz] [-a NAME]" 993 " [-g GRADE] [-s FILE] [-x NUM] command-string\n"), Progname); 994 exit(EX_USAGE); 995 } 996