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