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