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 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 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 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 */ 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 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