1 /*-
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1988, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)uux.c 8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17
18 #include "uucp.h"
19 #include <sys/stat.h>
20 #include <sysexits.h>
21
22 #define NOSYSPART 0
23 #define HASSYSPART 1
24
25 #define LQUOTE '('
26 #define RQUOTE ')'
27
28 #define APPCMD(d) {\
29 register char *p; for (p = d; *p != '\0';)\
30 {*cmdp++ = *p++;\
31 if(cmdp>(sizeof(cmd)+&cmd[0])){\
32 fprintf(stderr,"argument list too long\n");\
33 cleanup(EX_SOFTWARE);\
34 }\
35 }\
36 *cmdp++ = ' '; *cmdp = '\0';}
37
38 #define GENSEND(f, a, b, c, d, e) {\
39 fprintf(f, "S %s %s %s -%s %s 0666\n", a, b, c, d, e); }
40 #define GENRCV(f, a, b, c) {fprintf(f, "R %s %s %s - \n", a, b, c);}
41
42 struct timeb Now;
43
main(argc,argv)44 main(argc, argv)
45 int argc;
46 char **argv;
47 {
48 char cfile[NAMESIZE]; /* send commands for files from here */
49 char dfile[NAMESIZE]; /* used for all data files from here */
50 char rxfile[NAMESIZE]; /* to be sent to xqt file (X. ...) */
51 char tfile[NAMESIZE]; /* temporary file name */
52 char tcfile[NAMESIZE]; /* temporary file name */
53 char t2file[NAMESIZE]; /* temporary file name */
54 int cflag = 0; /* commands in C. file flag */
55 int rflag = 0; /* C. files for receiving flag */
56 #ifdef DONTCOPY
57 int Copy = 0; /* Don't Copy spool files */
58 #else !DONTCOPY
59 int Copy = 1; /* Copy spool files */
60 #endif !DONTCOPY
61 int Linkit = 0; /* Try link before copy */
62 char buf[2*BUFSIZ];
63 char inargs[2*BUFSIZ];
64 int pipein = 0;
65 int startjob = 1;
66 char Grade = 'A';
67 long Gradedelta = 100000000L; /* "huge number" */
68 long size = 0L;
69 char path[MAXFULLNAME];
70 char cmd[2*BUFSIZ];
71 char *ap, *cmdp;
72 char prm[2*BUFSIZ];
73 char syspart[MAXBASENAME+1], rest[MAXFULLNAME];
74 char Xsys[MAXBASENAME+1], local[MAXBASENAME+1];
75 char *xsys = Xsys;
76 FILE *fprx, *fpc, *fpd, *fp;
77 extern char *getprm(), *lastpart();
78 extern FILE *ufopen();
79 int uid, ret, c;
80 char redir = '\0';
81 int nonoti = 0;
82 int nonzero = 0;
83 int link_failed;
84 char *ReturnTo = NULL;
85 extern int LocalOnly;
86 extern char *optarg;
87 extern int optind;
88
89 strcpy(Progname, "uux");
90 uucpname(Myname);
91 umask(WFMASK);
92 Ofn = 1;
93 Ifn = 0;
94 #ifdef VMS
95 arg_fix(argc, argv);
96 #endif
97 while (((c = getopt(argc, argv, "-prclCg:x:nzLa:")) != EOF) ||
98 (optind < argc && (c = *argv[optind]) == '-' && ++optind))
99 switch (c) {
100 case '-':
101 /* FALLTHROUGH */
102 case 'p':
103 pipein = 1;
104 break;
105 case 'r':
106 startjob = 0;
107 break;
108 case 'c':
109 Copy = 0;
110 Linkit = 0;
111 break;
112 case 'l':
113 Copy = 0;
114 Linkit = 1;
115 break;
116 case 'C':
117 Copy = 1;
118 Linkit = 0;
119 break;
120 case 'g':
121 Grade = *optarg;
122 Gradedelta = atol(optarg+1);
123 break;
124 case 'x':
125 chkdebug();
126 Debug = atoi(optarg);
127 if (Debug <= 0)
128 Debug = 1;
129 break;
130 case 'n':
131 nonoti = 1;
132 break;
133 case 'z':
134 nonzero = 1;
135 break;
136 case 'L':
137 LocalOnly++;
138 break;
139 case 'a':
140 ReturnTo = optarg;
141 if (prefix(Myname, ReturnTo) && ReturnTo[strlen(Myname)] == '!')
142 ReturnTo = index(ReturnTo, '!') + 1;
143 break;
144 case '?':
145 default:
146 break;
147 }
148
149 ap = getwd(Wrkdir);
150 if (ap == 0) {
151 fprintf(stderr, "can't get working directory; will try to continue\n");
152 strcpy(Wrkdir, "/UNKNOWN");
153 }
154
155 DEBUG(4, "\n\n** %s **\n", "START");
156
157 inargs[0] = '\0';
158 while (optind < argc) {
159 DEBUG(4, "arg - %s:", argv[optind]);
160 strcat(inargs, " ");
161 strcat(inargs, argv[optind++]);
162 }
163 DEBUG(4, "arg - %s\n", inargs);
164 if (subchdir(Spool) < 0) {
165 syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool);
166 cleanup(1);
167 }
168 uid = getuid();
169 if (guinfo(uid, User, path) != SUCCESS) {
170 syslog(LOG_WARNING, "Can't find username for uid %d", uid);
171 DEBUG(1, "Using username", "uucp");
172 strcpy(User, "uucp");
173 }
174
175 strncpy(local, Myname, MAXBASENAME);
176 cmdp = cmd;
177 *cmdp = '\0';
178 gename(DATAPRE, local, 'X', rxfile);
179 fprx = ufopen(rxfile, "w");
180 if (fprx == NULL) {
181 syslog(LOG_WARNING, "fopen(%s) failed: %m", rxfile);
182 cleanup(1);
183 }
184 gename(DATAPRE, local, 'T', tcfile);
185 fpc = ufopen(tcfile, "w");
186 if (fpc == NULL) {
187 syslog(LOG_WARNING, "fopen(%s) failed: %m", tcfile);
188 cleanup(1);
189 }
190 fprintf(fprx, "%c %s %s\n", X_USER, User, local);
191 if (nonoti)
192 fprintf(fprx, "%c\n", X_NONOTI);
193 if (nonzero)
194 fprintf(fprx, "%c\n", X_NONZERO);
195 if (ReturnTo == NULL || *ReturnTo == '\0')
196 ReturnTo = User;
197 fprintf(fprx, "%c %s\n", X_RETURNTO, ReturnTo);
198
199 /* find remote system name */
200 ap = inargs;
201 xsys[0] = '\0';
202 while ((ap = getprm(ap, prm)) != NULL) {
203 if (prm[0] == '>' || prm[0] == '<') {
204 ap = getprm(ap, prm);
205 continue;
206 }
207
208 split(prm, xsys, rest);
209 break;
210 }
211 if (xsys[0] == '\0')
212 strcpy(xsys, local);
213 if (versys(&xsys) != 0) {
214 /* bad system name */
215 fprintf(stderr, "bad system name: %s\n", xsys);
216 fclose(fprx);
217 fclose(fpc);
218 cleanup(EX_NOHOST);
219 }
220
221 strncpy(Rmtname, xsys, MAXBASENAME);
222 DEBUG(4, "xsys %s\n", xsys);
223
224 if (pipein) {
225 gename(DATAPRE, local, 'B', dfile);
226 fpd = ufopen(dfile, "w");
227 if (fpd == NULL) {
228 syslog(LOG_WARNING, "fopen(%s) failed: %m", dfile);
229 cleanup(1);
230 }
231 while (!feof(stdin)) {
232 ret = fread(buf, 1, BUFSIZ, stdin);
233 fwrite(buf, 1, ret, fpd);
234 if (ferror(stdin)) {
235 perror("stdin");
236 cleanup(EX_IOERR);
237 }
238 if (ferror(fpd)) {
239 perror(dfile);
240 cleanup(EX_IOERR);
241 }
242 size += ret;
243 }
244 fclose(fpd);
245 strcpy(tfile, dfile);
246 if (strcmp(local, xsys) != SAME) {
247 register int Len = strlen(local);
248 if (Len > SYSNSIZE)
249 Len = SYSNSIZE;
250 tfile[Len + 2] = 'S';
251 GENSEND(fpc, dfile, tfile, User, "", dfile);
252 cflag++;
253 }
254 fprintf(fprx, "%c %s\n", X_RQDFILE, tfile);
255 fprintf(fprx, "%c %s\n", X_STDIN, tfile);
256 }
257 /* parse command */
258 ap = inargs;
259 while ((ap = getprm(ap, prm)) != NULL) {
260 DEBUG(4, "prm - %s\n", prm);
261 if (prm[0] == '>' || prm[0] == '<') {
262 redir = prm[0];
263 continue;
264 }
265
266 if (prm[0] == ';') {
267 APPCMD(prm);
268 continue;
269 }
270
271 if (prm[0] == '|' || prm[0] == '^') {
272 if (cmdp != cmd)
273 APPCMD(prm);
274 continue;
275 }
276
277 /* process command or file or option */
278 ret = split(prm, syspart, rest);
279 DEBUG(4, "s - %s, ", syspart);
280 DEBUG(4, "r - %s, ", rest);
281 DEBUG(4, "ret - %d\n", ret);
282 if (syspart[0] == '\0')
283 strcpy(syspart, local);
284
285 if (cmdp == cmd && redir == '\0') {
286 /* command */
287 APPCMD(rest);
288 continue;
289 }
290
291 /* process file or option */
292 DEBUG(4, "file s- %s, ", syspart);
293 DEBUG(4, "local - %s\n", local);
294 /* process file */
295 if (redir == '>') {
296 if (rest[0] != '~')
297 if (ckexpf(rest))
298 cleanup(EX_CANTCREAT);
299 fprintf(fprx, "%c %s %s\n", X_STDOUT, rest,
300 syspart);
301 redir = '\0';
302 continue;
303 }
304
305 if (ret == NOSYSPART && redir == '\0') {
306 /* option */
307 APPCMD(rest);
308 continue;
309 }
310
311 if (rest[0] != '\0') {
312 struct stat stbuf;
313 if (stat(rest, &stbuf) < 0)
314 DEBUG(4, "Can't stat %s\n", rest);
315 else
316 size += stbuf.st_size;
317 DEBUG(4, "size = %ld\n", size);
318 }
319
320 if (strcmp(xsys, local) == SAME
321 && strcmp(xsys, syspart) == SAME) {
322 if (ckexpf(rest))
323 cleanup(EX_CANTCREAT);
324 if (redir == '<')
325 fprintf(fprx, "%c %s\n", X_STDIN, rest);
326 else
327 APPCMD(rest);
328 redir = '\0';
329 continue;
330 }
331
332 if (strcmp(syspart, local) == SAME) {
333 /* generate send file */
334 if (ckexpf(rest))
335 cleanup(EX_CANTCREAT);
336 gename(DATAPRE, local, 'A', dfile);
337 DEBUG(4, "rest %s\n", rest);
338 if ((chkpth(User, "", rest) || anyread(rest)) != 0) {
339 fprintf(stderr, "permission denied %s\n", rest);
340 cleanup(EX_NOINPUT);
341 }
342 link_failed = 0;
343 if (Linkit) {
344 if (link(subfile(rest), subfile(dfile)) != 0)
345 link_failed++;
346 else
347 GENSEND(fpc, rest, dfile, User, "", dfile);
348 }
349 if (Copy || link_failed) {
350 if (xcp(rest, dfile) != 0) {
351 fprintf(stderr, "can't copy %s to %s\n", rest, dfile);
352 cleanup(EX_NOINPUT);
353 }
354 GENSEND(fpc, rest, dfile, User, "", dfile);
355 }
356 if (!Copy && !Linkit) {
357 GENSEND(fpc, rest, dfile, User, "c", "D.0");
358 }
359 cflag++;
360 if (redir == '<') {
361 fprintf(fprx, "%c %s\n", X_STDIN, dfile);
362 fprintf(fprx, "%c %s\n", X_RQDFILE, dfile);
363 } else {
364 APPCMD(lastpart(rest));
365 fprintf(fprx, "%c %s %s\n", X_RQDFILE,
366 dfile, lastpart(rest));
367 }
368 redir = '\0';
369 continue;
370 }
371
372 if (strcmp(local, xsys) == SAME) {
373 /* generate local receive */
374 gename(CMDPRE, syspart, 'R', tfile);
375 strcpy(dfile, tfile);
376 dfile[0] = DATAPRE;
377 fp = ufopen(tfile, "w");
378 if (fp == NULL) {
379 syslog(LOG_WARNING, "fopen(%s) failed: %m",
380 tfile);
381 cleanup(1);
382 }
383 if (ckexpf(rest))
384 cleanup(EX_CANTCREAT);
385 GENRCV(fp, rest, dfile, User);
386 fclose(fp);
387 rflag++;
388 if (rest[0] != '~')
389 if (ckexpf(rest))
390 cleanup(EX_CANTCREAT);
391 if (redir == '<') {
392 fprintf(fprx, "%c %s\n", X_RQDFILE, dfile);
393 fprintf(fprx, "%c %s\n", X_STDIN, dfile);
394 } else {
395 fprintf(fprx, "%c %s %s\n", X_RQDFILE, dfile,
396 lastpart(rest));
397 APPCMD(lastpart(rest));
398 }
399
400 redir = '\0';
401 continue;
402 }
403
404 if (strcmp(syspart, xsys) != SAME) {
405 /* generate remote receives */
406 gename(DATAPRE, syspart, 'R', dfile);
407 strcpy(tfile, dfile);
408 tfile[0] = CMDPRE;
409 fpd = ufopen(dfile, "w");
410 if (fpd == NULL) {
411 syslog(LOG_WARNING, "fopen(%s) failed: %m",
412 dfile);
413 cleanup(1);
414 }
415 gename(DATAPRE, local, 'T', t2file);
416 GENRCV(fpd, rest, t2file, User);
417 fclose(fpd);
418 GENSEND(fpc, dfile, tfile, User, "", dfile);
419 cflag++;
420 if (redir == '<') {
421 fprintf(fprx, "%c %s\n", X_RQDFILE, t2file);
422 fprintf(fprx, "%c %s\n", X_STDIN, t2file);
423 } else {
424 fprintf(fprx, "%c %s %s\n", X_RQDFILE, t2file,
425 lastpart(rest));
426 APPCMD(lastpart(rest));
427 }
428 redir = '\0';
429 continue;
430 }
431
432 /* file on remote system */
433 if (rest[0] != '~')
434 if (ckexpf(rest))
435 cleanup(EX_CANTCREAT);
436 if (redir == '<')
437 fprintf(fprx, "%c %s\n", X_STDIN, rest);
438 else
439 APPCMD(rest);
440 redir = '\0';
441 continue;
442
443 }
444 /*
445 * clean up trailing ' ' in command.
446 */
447 if (cmdp > cmd && cmdp[0] == '\0' && cmdp[-1] == ' ')
448 *--cmdp = '\0';
449 /* block multi-hop uux, which doesn't work */
450 for (ap = cmd; *ap && *ap != ' '; ap++)
451 if (*ap == '!') {
452 fprintf(stderr, "uux handles only adjacent sites.\n");
453 fprintf(stderr, "Try uusend for multi-hop delivery.\n");
454 cleanup(EX_USAGE);
455 }
456
457 fprintf(fprx, "%c %s\n", X_CMD, cmd);
458 if (ferror(fprx)) {
459 logent(cmd, "COULD NOT QUEUE XQT");
460 cleanup(EX_IOERR);
461 } else
462 logent(cmd, "XQT QUE'D");
463 fclose(fprx);
464
465 if (size > 0 && Gradedelta > 0) {
466 DEBUG (4, "Grade changed from %c ", Grade);
467 Grade += size/Gradedelta;
468 if (Grade > 'z')
469 Grade = 'z';
470 DEBUG(4, "to %c\n", Grade);
471 }
472 gename(XQTPRE, local, Grade, tfile);
473 if (strcmp(xsys, local) == SAME) {
474 /* rti!trt: xmv() works across filesystems, link(II) doesnt */
475 xmv(rxfile, tfile);
476 if (startjob)
477 if (rflag)
478 xuucico(xsys);
479 else
480 xuuxqt();
481 }
482 else {
483 GENSEND(fpc, rxfile, tfile, User, "", rxfile);
484 cflag++;
485 }
486
487 if (ferror(fpc))
488 cleanup(EX_IOERR);
489 fclose(fpc);
490 if (cflag) {
491 gename(CMDPRE, xsys, Grade, cfile);
492 /* rti!trt: use xmv() rather than link(II) */
493 xmv(tcfile, cfile);
494 if (startjob)
495 xuucico(xsys);
496 cleanup(0);
497 }
498 else
499 unlink(subfile(tcfile));
500 exit(0);
501 }
502
503 #define FTABSIZE 30
504 char Fname[FTABSIZE][NAMESIZE];
505 int Fnamect = 0;
506
507 /*
508 * cleanup and unlink if error
509 *
510 * return - none - do exit()
511 */
512
cleanup(code)513 cleanup(code)
514 int code;
515 {
516 int i;
517
518 logcls();
519 rmlock(CNULL);
520 if (code) {
521 for (i = 0; i < Fnamect; i++)
522 unlink(subfile(Fname[i]));
523 fprintf(stderr, "uux failed. code %d\n", code);
524 }
525 DEBUG(1, "exit code %d\n", code);
526 exit(code);
527 }
528
529 /*
530 * open file and record name
531 *
532 * return file pointer.
533 */
534
ufopen(file,mode)535 FILE *ufopen(file, mode)
536 char *file, *mode;
537 {
538 if (Fnamect < FTABSIZE)
539 strcpy(Fname[Fnamect++], file);
540 else
541 logent("Fname", "TABLE OVERFLOW");
542 return fopen(subfile(file), mode);
543 }
544 #ifdef VMS
545 /*
546 * EUNICE bug:
547 * quotes are not stripped from DCL. Do it here.
548 * Note if we are running under Unix shell we don't
549 * do the right thing.
550 */
arg_fix(argc,argv)551 arg_fix(argc, argv)
552 char **argv;
553 {
554 register char *cp, *tp;
555
556 for (; argc > 0; --argc, argv++) {
557 cp = *argv;
558 if (cp == (char *)0 || *cp++ != '"')
559 continue;
560 tp = cp;
561 while (*tp++) ;
562 tp -= 2;
563 if (*tp == '"') {
564 *tp = '\0';
565 *argv = cp;
566 }
567 }
568 }
569 #endif VMS
570
571 /*
572 * split into system and file part
573 *
574 * return codes:
575 * NOSYSPART
576 * HASSYSPART
577 */
578
split(name,sys,rest)579 split(name, sys, rest)
580 register char *name, *rest;
581 char *sys;
582 {
583 register char *c;
584
585 if (*name == LQUOTE) {
586 if ((c = index(name + 1, RQUOTE)) != NULL) {
587 /* strip off quotes */
588 name++;
589 while (c != name)
590 *rest++ = *name++;
591 *rest = '\0';
592 *sys = '\0';
593 return NOSYSPART;
594 }
595 }
596
597 if ((c = index(name, '!')) == NULL) {
598 strcpy(rest, name);
599 *sys = '\0';
600 return NOSYSPART;
601 }
602
603 *c++ = '\0';
604 strncpy(sys, name, MAXBASENAME);
605 sys[MAXBASENAME] = '\0';
606
607 strcpy(rest, c);
608 return HASSYSPART;
609 }
610