xref: /original-bsd/usr.bin/tip/cmds.c (revision 0a83ae40)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)cmds.c	5.6 (Berkeley) 12/22/87";
9 #endif not lint
10 
11 #include "tip.h"
12 /*
13  * tip
14  *
15  * miscellaneous commands
16  */
17 
18 int	quant[] = { 60, 60, 24 };
19 
20 char	null = '\0';
21 char	*sep[] = { "second", "minute", "hour" };
22 static char *argv[10];		/* argument vector for take and put */
23 
24 int	timeout();		/* timeout function called on alarm */
25 int	stopsnd();		/* SIGINT handler during file transfers */
26 int	intprompt();		/* used in handling SIG_INT during prompt */
27 int	intcopy();		/* interrupt routine for file transfers */
28 
29 /*
30  * FTP - remote ==> local
31  *  get a file from the remote host
32  */
33 getfl(c)
34 	char c;
35 {
36 	char buf[256], *cp, *expand();
37 
38 	putchar(c);
39 	/*
40 	 * get the UNIX receiving file's name
41 	 */
42 	if (prompt("Local file name? ", copyname))
43 		return;
44 	cp = expand(copyname);
45 	if ((sfd = creat(cp, 0666)) < 0) {
46 		printf("\r\n%s: cannot creat\r\n", copyname);
47 		return;
48 	}
49 
50 	/*
51 	 * collect parameters
52 	 */
53 	if (prompt("List command for remote system? ", buf)) {
54 		unlink(copyname);
55 		return;
56 	}
57 	transfer(buf, sfd, value(EOFREAD));
58 }
59 
60 /*
61  * Cu-like take command
62  */
63 cu_take(cc)
64 	char cc;
65 {
66 	int fd, argc;
67 	char line[BUFSIZ], *expand(), *cp;
68 
69 	if (prompt("[take] ", copyname))
70 		return;
71 	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
72 		printf("usage: <take> from [to]\r\n");
73 		return;
74 	}
75 	if (argc == 1)
76 		argv[1] = argv[0];
77 	cp = expand(argv[1]);
78 	if ((fd = creat(cp, 0666)) < 0) {
79 		printf("\r\n%s: cannot create\r\n", argv[1]);
80 		return;
81 	}
82 	sprintf(line, "cat %s;echo \01", argv[0]);
83 	transfer(line, fd, "\01");
84 }
85 
86 static	jmp_buf intbuf;
87 /*
88  * Bulk transfer routine --
89  *  used by getfl(), cu_take(), and pipefile()
90  */
91 transfer(buf, fd, eofchars)
92 	char *buf, *eofchars;
93 {
94 	register int ct;
95 	char c, buffer[BUFSIZ];
96 	register char *p = buffer;
97 	register int cnt, eof;
98 	time_t start;
99 	int (*f)();
100 
101 	pwrite(FD, buf, size(buf));
102 	quit = 0;
103 	kill(pid, SIGIOT);
104 	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
105 
106 	/*
107 	 * finish command
108 	 */
109 	pwrite(FD, "\r", 1);
110 	do
111 		read(FD, &c, 1);
112 	while ((c&0177) != '\n');
113 	ioctl(0, TIOCSETC, &defchars);
114 
115 	(void) setjmp(intbuf);
116 	f = signal(SIGINT, intcopy);
117 	start = time(0);
118 	for (ct = 0; !quit;) {
119 		eof = read(FD, &c, 1) <= 0;
120 		c &= 0177;
121 		if (quit)
122 			continue;
123 		if (eof || any(c, eofchars))
124 			break;
125 		if (c == 0)
126 			continue;	/* ignore nulls */
127 		if (c == '\r')
128 			continue;
129 		*p++ = c;
130 
131 		if (c == '\n' && boolean(value(VERBOSE)))
132 			printf("\r%d", ++ct);
133 		if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
134 			if (write(fd, buffer, cnt) != cnt) {
135 				printf("\r\nwrite error\r\n");
136 				quit = 1;
137 			}
138 			p = buffer;
139 		}
140 	}
141 	if (cnt = (p-buffer))
142 		if (write(fd, buffer, cnt) != cnt)
143 			printf("\r\nwrite error\r\n");
144 
145 	if (boolean(value(VERBOSE)))
146 		prtime(" lines transferred in ", time(0)-start);
147 	ioctl(0, TIOCSETC, &tchars);
148 	write(fildes[1], (char *)&ccc, 1);
149 	signal(SIGINT, f);
150 	close(fd);
151 }
152 
153 /*
154  * FTP - remote ==> local process
155  *   send remote input to local process via pipe
156  */
157 pipefile()
158 {
159 	int cpid, pdes[2];
160 	char buf[256];
161 	int status, p;
162 	extern int errno;
163 
164 	if (prompt("Local command? ", buf))
165 		return;
166 
167 	if (pipe(pdes)) {
168 		printf("can't establish pipe\r\n");
169 		return;
170 	}
171 
172 	if ((cpid = fork()) < 0) {
173 		printf("can't fork!\r\n");
174 		return;
175 	} else if (cpid) {
176 		if (prompt("List command for remote system? ", buf)) {
177 			close(pdes[0]), close(pdes[1]);
178 			kill (cpid, SIGKILL);
179 		} else {
180 			close(pdes[0]);
181 			signal(SIGPIPE, intcopy);
182 			transfer(buf, pdes[1], value(EOFREAD));
183 			signal(SIGPIPE, SIG_DFL);
184 			while ((p = wait(&status)) > 0 && p != cpid)
185 				;
186 		}
187 	} else {
188 		register int f;
189 
190 		dup2(pdes[0], 0);
191 		close(pdes[0]);
192 		for (f = 3; f < 20; f++)
193 			close(f);
194 		execute(buf);
195 		printf("can't execl!\r\n");
196 		exit(0);
197 	}
198 }
199 
200 /*
201  * Interrupt service routine for FTP
202  */
203 stopsnd()
204 {
205 
206 	stop = 1;
207 	signal(SIGINT, SIG_IGN);
208 }
209 
210 /*
211  * FTP - local ==> remote
212  *  send local file to remote host
213  *  terminate transmission with pseudo EOF sequence
214  */
215 sendfile(cc)
216 	char cc;
217 {
218 	FILE *fd;
219 	char *fnamex;
220 	char *expand();
221 
222 	putchar(cc);
223 	/*
224 	 * get file name
225 	 */
226 	if (prompt("Local file name? ", fname))
227 		return;
228 
229 	/*
230 	 * look up file
231 	 */
232 	fnamex = expand(fname);
233 	if ((fd = fopen(fnamex, "r")) == NULL) {
234 		printf("%s: cannot open\r\n", fname);
235 		return;
236 	}
237 	transmit(fd, value(EOFWRITE), NULL);
238 	if (!boolean(value(ECHOCHECK))) {
239 		struct sgttyb buf;
240 
241 		ioctl(FD, TIOCGETP, &buf);	/* this does a */
242 		ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
243 	}
244 }
245 
246 /*
247  * Bulk transfer routine to remote host --
248  *   used by sendfile() and cu_put()
249  */
250 transmit(fd, eofchars, command)
251 	FILE *fd;
252 	char *eofchars, *command;
253 {
254 	char *pc, lastc;
255 	int c, ccount, lcount;
256 	time_t start_t, stop_t;
257 	int (*f)();
258 
259 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
260 	stop = 0;
261 	f = signal(SIGINT, stopsnd);
262 	ioctl(0, TIOCSETC, &defchars);
263 	read(repdes[0], (char *)&ccc, 1);
264 	if (command != NULL) {
265 		for (pc = command; *pc; pc++)
266 			send(*pc);
267 		if (boolean(value(ECHOCHECK)))
268 			read(FD, (char *)&c, 1);	/* trailing \n */
269 		else {
270 			struct sgttyb buf;
271 
272 			ioctl(FD, TIOCGETP, &buf);	/* this does a */
273 			ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
274 			sleep(5); /* wait for remote stty to take effect */
275 		}
276 	}
277 	lcount = 0;
278 	lastc = '\0';
279 	start_t = time(0);
280 	while (1) {
281 		ccount = 0;
282 		do {
283 			c = getc(fd);
284 			if (stop)
285 				goto out;
286 			if (c == EOF)
287 				goto out;
288 			if (c == 0177 && !boolean(value(RAWFTP)))
289 				continue;
290 			lastc = c;
291 			if (c < 040) {
292 				if (c == '\n') {
293 					if (!boolean(value(RAWFTP)))
294 						c = '\r';
295 				}
296 				else if (c == '\t') {
297 					if (!boolean(value(RAWFTP))) {
298 						if (boolean(value(TABEXPAND))) {
299 							send(' ');
300 							while ((++ccount % 8) != 0)
301 								send(' ');
302 							continue;
303 						}
304 					}
305 				} else
306 					if (!boolean(value(RAWFTP)))
307 						continue;
308 			}
309 			send(c);
310 		} while (c != '\r' && !boolean(value(RAWFTP)));
311 		if (boolean(value(VERBOSE)))
312 			printf("\r%d", ++lcount);
313 		if (boolean(value(ECHOCHECK))) {
314 			timedout = 0;
315 			alarm(value(ETIMEOUT));
316 			do {	/* wait for prompt */
317 				read(FD, (char *)&c, 1);
318 				if (timedout || stop) {
319 					if (timedout)
320 						printf("\r\ntimed out at eol\r\n");
321 					alarm(0);
322 					goto out;
323 				}
324 			} while ((c&0177) != character(value(PROMPT)));
325 			alarm(0);
326 		}
327 	}
328 out:
329 	if (lastc != '\n' && !boolean(value(RAWFTP)))
330 		send('\r');
331 	for (pc = eofchars; *pc; pc++)
332 		send(*pc);
333 	stop_t = time(0);
334 	fclose(fd);
335 	signal(SIGINT, f);
336 	if (boolean(value(VERBOSE)))
337 		if (boolean(value(RAWFTP)))
338 			prtime(" chars transferred in ", stop_t-start_t);
339 		else
340 			prtime(" lines transferred in ", stop_t-start_t);
341 	write(fildes[1], (char *)&ccc, 1);
342 	ioctl(0, TIOCSETC, &tchars);
343 }
344 
345 /*
346  * Cu-like put command
347  */
348 cu_put(cc)
349 	char cc;
350 {
351 	FILE *fd;
352 	char line[BUFSIZ];
353 	int argc;
354 	char *expand();
355 	char *copynamex;
356 
357 	if (prompt("[put] ", copyname))
358 		return;
359 	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
360 		printf("usage: <put> from [to]\r\n");
361 		return;
362 	}
363 	if (argc == 1)
364 		argv[1] = argv[0];
365 	copynamex = expand(argv[0]);
366 	if ((fd = fopen(copynamex, "r")) == NULL) {
367 		printf("%s: cannot open\r\n", copynamex);
368 		return;
369 	}
370 	if (boolean(value(ECHOCHECK)))
371 		sprintf(line, "cat>%s\r", argv[1]);
372 	else
373 		sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
374 	transmit(fd, "\04", line);
375 }
376 
377 /*
378  * FTP - send single character
379  *  wait for echo & handle timeout
380  */
381 send(c)
382 	char c;
383 {
384 	char cc;
385 	int retry = 0;
386 
387 	cc = c;
388 	pwrite(FD, &cc, 1);
389 #ifdef notdef
390 	if (number(value(CDELAY)) > 0 && c != '\r')
391 		nap(number(value(CDELAY)));
392 #endif
393 	if (!boolean(value(ECHOCHECK))) {
394 #ifdef notdef
395 		if (number(value(LDELAY)) > 0 && c == '\r')
396 			nap(number(value(LDELAY)));
397 #endif
398 		return;
399 	}
400 tryagain:
401 	timedout = 0;
402 	alarm(value(ETIMEOUT));
403 	read(FD, &cc, 1);
404 	alarm(0);
405 	if (timedout) {
406 		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
407 		if (retry++ > 3)
408 			return;
409 		pwrite(FD, &null, 1); /* poke it */
410 		goto tryagain;
411 	}
412 }
413 
414 timeout()
415 {
416 	signal(SIGALRM, timeout);
417 	timedout = 1;
418 }
419 
420 /*
421  * Stolen from consh() -- puts a remote file on the output of a local command.
422  *	Identical to consh() except for where stdout goes.
423  */
424 pipeout(c)
425 {
426 	char buf[256];
427 	int cpid, status, p;
428 	time_t start;
429 
430 	putchar(c);
431 	if (prompt("Local command? ", buf))
432 		return;
433 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
434 	signal(SIGINT, SIG_IGN);
435 	signal(SIGQUIT, SIG_IGN);
436 	ioctl(0, TIOCSETC, &defchars);
437 	read(repdes[0], (char *)&ccc, 1);
438 	/*
439 	 * Set up file descriptors in the child and
440 	 *  let it go...
441 	 */
442 	if ((cpid = fork()) < 0)
443 		printf("can't fork!\r\n");
444 	else if (cpid) {
445 		start = time(0);
446 		while ((p = wait(&status)) > 0 && p != cpid)
447 			;
448 	} else {
449 		register int i;
450 
451 		dup2(FD, 1);
452 		for (i = 3; i < 20; i++)
453 			close(i);
454 		signal(SIGINT, SIG_DFL);
455 		signal(SIGQUIT, SIG_DFL);
456 		execute(buf);
457 		printf("can't find `%s'\r\n", buf);
458 		exit(0);
459 	}
460 	if (boolean(value(VERBOSE)))
461 		prtime("away for ", time(0)-start);
462 	write(fildes[1], (char *)&ccc, 1);
463 	ioctl(0, TIOCSETC, &tchars);
464 	signal(SIGINT, SIG_DFL);
465 	signal(SIGQUIT, SIG_DFL);
466 }
467 
468 #ifdef CONNECT
469 /*
470  * Fork a program with:
471  *  0 <-> local tty in
472  *  1 <-> local tty out
473  *  2 <-> local tty out
474  *  3 <-> remote tty in
475  *  4 <-> remote tty out
476  */
477 consh(c)
478 {
479 	char buf[256];
480 	int cpid, status, p;
481 	time_t start;
482 
483 	putchar(c);
484 	if (prompt("Local command? ", buf))
485 		return;
486 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
487 	signal(SIGINT, SIG_IGN);
488 	signal(SIGQUIT, SIG_IGN);
489 	ioctl(0, TIOCSETC, &defchars);
490 	read(repdes[0], (char *)&ccc, 1);
491 	/*
492 	 * Set up file descriptors in the child and
493 	 *  let it go...
494 	 */
495 	if ((cpid = fork()) < 0)
496 		printf("can't fork!\r\n");
497 	else if (cpid) {
498 		start = time(0);
499 		while ((p = wait(&status)) > 0 && p != cpid)
500 			;
501 	} else {
502 		register int i;
503 
504 		dup2(FD, 3);
505 		dup2(3, 4);
506 		for (i = 5; i < 20; i++)
507 			close(i);
508 		signal(SIGINT, SIG_DFL);
509 		signal(SIGQUIT, SIG_DFL);
510 		execute(buf);
511 		printf("can't find `%s'\r\n", buf);
512 		exit(0);
513 	}
514 	if (boolean(value(VERBOSE)))
515 		prtime("away for ", time(0)-start);
516 	write(fildes[1], (char *)&ccc, 1);
517 	ioctl(0, TIOCSETC, &tchars);
518 	signal(SIGINT, SIG_DFL);
519 	signal(SIGQUIT, SIG_DFL);
520 }
521 #endif
522 
523 /*
524  * Escape to local shell
525  */
526 shell()
527 {
528 	int shpid, status;
529 	extern char **environ;
530 	char *cp;
531 
532 	printf("[sh]\r\n");
533 	signal(SIGINT, SIG_IGN);
534 	signal(SIGQUIT, SIG_IGN);
535 	unraw();
536 	if (shpid = fork()) {
537 		while (shpid != wait(&status));
538 		raw();
539 		printf("\r\n!\r\n");
540 		signal(SIGINT, SIG_DFL);
541 		signal(SIGQUIT, SIG_DFL);
542 		return;
543 	} else {
544 		signal(SIGQUIT, SIG_DFL);
545 		signal(SIGINT, SIG_DFL);
546 		if ((cp = rindex(value(SHELL), '/')) == NULL)
547 			cp = value(SHELL);
548 		else
549 			cp++;
550 		shell_uid();
551 		execl(value(SHELL), cp, 0);
552 		printf("\r\ncan't execl!\r\n");
553 		exit(1);
554 	}
555 }
556 
557 /*
558  * TIPIN portion of scripting
559  *   initiate the conversation with TIPOUT
560  */
561 setscript()
562 {
563 	char c;
564 	/*
565 	 * enable TIPOUT side for dialogue
566 	 */
567 	kill(pid, SIGEMT);
568 	if (boolean(value(SCRIPT)))
569 		write(fildes[1], value(RECORD), size(value(RECORD)));
570 	write(fildes[1], "\n", 1);
571 	/*
572 	 * wait for TIPOUT to finish
573 	 */
574 	read(repdes[0], &c, 1);
575 	if (c == 'n')
576 		printf("can't create %s\r\n", value(RECORD));
577 }
578 
579 /*
580  * Change current working directory of
581  *   local portion of tip
582  */
583 chdirectory()
584 {
585 	char dirname[80];
586 	register char *cp = dirname;
587 
588 	if (prompt("[cd] ", dirname)) {
589 		if (stoprompt)
590 			return;
591 		cp = value(HOME);
592 	}
593 	if (chdir(cp) < 0)
594 		printf("%s: bad directory\r\n", cp);
595 	printf("!\r\n");
596 }
597 
598 abort(msg)
599 	char *msg;
600 {
601 
602 	kill(pid, SIGTERM);
603 	disconnect(msg);
604 	if (msg != NOSTR)
605 		printf("\r\n%s", msg);
606 	printf("\r\n[EOT]\r\n");
607 	daemon_uid();
608 	delock(uucplock);
609 	unraw();
610 	exit(0);
611 }
612 
613 finish()
614 {
615 	char *dismsg;
616 
617 	if ((dismsg = value(DISCONNECT)) != NOSTR) {
618 		write(FD, dismsg, strlen(dismsg));
619 		sleep(5);
620 	}
621 	abort(NOSTR);
622 }
623 
624 intcopy()
625 {
626 
627 	raw();
628 	quit = 1;
629 	longjmp(intbuf, 1);
630 }
631 
632 execute(s)
633 	char *s;
634 {
635 	register char *cp;
636 
637 	if ((cp = rindex(value(SHELL), '/')) == NULL)
638 		cp = value(SHELL);
639 	else
640 		cp++;
641 	user_uid();
642 	execl(value(SHELL), cp, "-c", s, 0);
643 }
644 
645 args(buf, a)
646 	char *buf, *a[];
647 {
648 	register char *p = buf, *start;
649 	register char **parg = a;
650 	register int n = 0;
651 
652 	do {
653 		while (*p && (*p == ' ' || *p == '\t'))
654 			p++;
655 		start = p;
656 		if (*p)
657 			*parg = p;
658 		while (*p && (*p != ' ' && *p != '\t'))
659 			p++;
660 		if (p != start)
661 			parg++, n++;
662 		if (*p)
663 			*p++ = '\0';
664 	} while (*p);
665 
666 	return(n);
667 }
668 
669 prtime(s, a)
670 	char *s;
671 	time_t a;
672 {
673 	register i;
674 	int nums[3];
675 
676 	for (i = 0; i < 3; i++) {
677 		nums[i] = (int)(a % quant[i]);
678 		a /= quant[i];
679 	}
680 	printf("%s", s);
681 	while (--i >= 0)
682 		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
683 			printf("%d %s%c ", nums[i], sep[i],
684 				nums[i] == 1 ? '\0' : 's');
685 	printf("\r\n!\r\n");
686 }
687 
688 variable()
689 {
690 	char	buf[256];
691 
692 	if (prompt("[set] ", buf))
693 		return;
694 	vlex(buf);
695 	if (vtable[BEAUTIFY].v_access&CHANGED) {
696 		vtable[BEAUTIFY].v_access &= ~CHANGED;
697 		kill(pid, SIGSYS);
698 	}
699 	if (vtable[SCRIPT].v_access&CHANGED) {
700 		vtable[SCRIPT].v_access &= ~CHANGED;
701 		setscript();
702 		/*
703 		 * So that "set record=blah script" doesn't
704 		 *  cause two transactions to occur.
705 		 */
706 		if (vtable[RECORD].v_access&CHANGED)
707 			vtable[RECORD].v_access &= ~CHANGED;
708 	}
709 	if (vtable[RECORD].v_access&CHANGED) {
710 		vtable[RECORD].v_access &= ~CHANGED;
711 		if (boolean(value(SCRIPT)))
712 			setscript();
713 	}
714 	if (vtable[TAND].v_access&CHANGED) {
715 		vtable[TAND].v_access &= ~CHANGED;
716 		if (boolean(value(TAND)))
717 			tandem("on");
718 		else
719 			tandem("off");
720 	}
721  	if (vtable[LECHO].v_access&CHANGED) {
722  		vtable[LECHO].v_access &= ~CHANGED;
723  		HD = boolean(value(LECHO));
724  	}
725 	if (vtable[PARITY].v_access&CHANGED) {
726 		vtable[PARITY].v_access &= ~CHANGED;
727 		setparity();
728 	}
729 }
730 
731 /*
732  * Turn tandem mode on or off for remote tty.
733  */
734 tandem(option)
735 	char *option;
736 {
737 	struct sgttyb rmtty;
738 
739 	ioctl(FD, TIOCGETP, &rmtty);
740 	if (strcmp(option,"on") == 0) {
741 		rmtty.sg_flags |= TANDEM;
742 		arg.sg_flags |= TANDEM;
743 	} else {
744 		rmtty.sg_flags &= ~TANDEM;
745 		arg.sg_flags &= ~TANDEM;
746 	}
747 	ioctl(FD, TIOCSETP, &rmtty);
748 	ioctl(0,  TIOCSETP, &arg);
749 }
750 
751 /*
752  * Send a break.
753  */
754 genbrk()
755 {
756 
757 	ioctl(FD, TIOCSBRK, NULL);
758 	sleep(1);
759 	ioctl(FD, TIOCCBRK, NULL);
760 }
761 
762 /*
763  * Suspend tip
764  */
765 suspend(c)
766 	char c;
767 {
768 
769 	unraw();
770 	kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
771 	raw();
772 }
773 
774 /*
775  *	expand a file name if it includes shell meta characters
776  */
777 
778 char *
779 expand(name)
780 	char name[];
781 {
782 	static char xname[BUFSIZ];
783 	char cmdbuf[BUFSIZ];
784 	register int pid, l, rc;
785 	register char *cp, *Shell;
786 	int s, pivec[2], (*sigint)();
787 
788 	if (!anyof(name, "~{[*?$`'\"\\"))
789 		return(name);
790 	/* sigint = signal(SIGINT, SIG_IGN); */
791 	if (pipe(pivec) < 0) {
792 		perror("pipe");
793 		/* signal(SIGINT, sigint) */
794 		return(name);
795 	}
796 	sprintf(cmdbuf, "echo %s", name);
797 	if ((pid = vfork()) == 0) {
798 		Shell = value(SHELL);
799 		if (Shell == NOSTR)
800 			Shell = "/bin/sh";
801 		close(pivec[0]);
802 		close(1);
803 		dup(pivec[1]);
804 		close(pivec[1]);
805 		close(2);
806 		shell_uid();
807 		execl(Shell, Shell, "-c", cmdbuf, 0);
808 		_exit(1);
809 	}
810 	if (pid == -1) {
811 		perror("fork");
812 		close(pivec[0]);
813 		close(pivec[1]);
814 		return(NOSTR);
815 	}
816 	close(pivec[1]);
817 	l = read(pivec[0], xname, BUFSIZ);
818 	close(pivec[0]);
819 	while (wait(&s) != pid);
820 		;
821 	s &= 0377;
822 	if (s != 0 && s != SIGPIPE) {
823 		fprintf(stderr, "\"Echo\" failed\n");
824 		return(NOSTR);
825 	}
826 	if (l < 0) {
827 		perror("read");
828 		return(NOSTR);
829 	}
830 	if (l == 0) {
831 		fprintf(stderr, "\"%s\": No match\n", name);
832 		return(NOSTR);
833 	}
834 	if (l == BUFSIZ) {
835 		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
836 		return(NOSTR);
837 	}
838 	xname[l] = 0;
839 	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
840 		;
841 	*++cp = '\0';
842 	return(xname);
843 }
844 
845 /*
846  * Are any of the characters in the two strings the same?
847  */
848 
849 anyof(s1, s2)
850 	register char *s1, *s2;
851 {
852 	register int c;
853 
854 	while (c = *s1++)
855 		if (any(c, s2))
856 			return(1);
857 	return(0);
858 }
859