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
main(argc,argv,envp)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
cleanup(code)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
onintr(inter)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
usage()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