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