xref: /original-bsd/usr.bin/tip/cmds.c (revision 0fc6f013)
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.4 (Berkeley) 05/05/86";
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 		execl(value(SHELL), cp, 0);
551 		printf("\r\ncan't execl!\r\n");
552 		exit(1);
553 	}
554 }
555 
556 /*
557  * TIPIN portion of scripting
558  *   initiate the conversation with TIPOUT
559  */
560 setscript()
561 {
562 	char c;
563 	/*
564 	 * enable TIPOUT side for dialogue
565 	 */
566 	kill(pid, SIGEMT);
567 	if (boolean(value(SCRIPT)))
568 		write(fildes[1], value(RECORD), size(value(RECORD)));
569 	write(fildes[1], "\n", 1);
570 	/*
571 	 * wait for TIPOUT to finish
572 	 */
573 	read(repdes[0], &c, 1);
574 	if (c == 'n')
575 		printf("can't create %s\r\n", value(RECORD));
576 }
577 
578 /*
579  * Change current working directory of
580  *   local portion of tip
581  */
582 chdirectory()
583 {
584 	char dirname[80];
585 	register char *cp = dirname;
586 
587 	if (prompt("[cd] ", dirname)) {
588 		if (stoprompt)
589 			return;
590 		cp = value(HOME);
591 	}
592 	if (chdir(cp) < 0)
593 		printf("%s: bad directory\r\n", cp);
594 	printf("!\r\n");
595 }
596 
597 abort(msg)
598 	char *msg;
599 {
600 
601 	kill(pid, SIGTERM);
602 	setreuid(euid, euid);
603 	setregid(egid, egid);
604 	disconnect(msg);
605 	if (msg != NOSTR)
606 		printf("\r\n%s", msg);
607 	printf("\r\n[EOT]\r\n");
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 	execl(value(SHELL), cp, "-c", s, 0);
642 }
643 
644 args(buf, a)
645 	char *buf, *a[];
646 {
647 	register char *p = buf, *start;
648 	register char **parg = a;
649 	register int n = 0;
650 
651 	do {
652 		while (*p && (*p == ' ' || *p == '\t'))
653 			p++;
654 		start = p;
655 		if (*p)
656 			*parg = p;
657 		while (*p && (*p != ' ' && *p != '\t'))
658 			p++;
659 		if (p != start)
660 			parg++, n++;
661 		if (*p)
662 			*p++ = '\0';
663 	} while (*p);
664 
665 	return(n);
666 }
667 
668 prtime(s, a)
669 	char *s;
670 	time_t a;
671 {
672 	register i;
673 	int nums[3];
674 
675 	for (i = 0; i < 3; i++) {
676 		nums[i] = (int)(a % quant[i]);
677 		a /= quant[i];
678 	}
679 	printf("%s", s);
680 	while (--i >= 0)
681 		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
682 			printf("%d %s%c ", nums[i], sep[i],
683 				nums[i] == 1 ? '\0' : 's');
684 	printf("\r\n!\r\n");
685 }
686 
687 variable()
688 {
689 	char	buf[256];
690 
691 	if (prompt("[set] ", buf))
692 		return;
693 	vlex(buf);
694 	if (vtable[BEAUTIFY].v_access&CHANGED) {
695 		vtable[BEAUTIFY].v_access &= ~CHANGED;
696 		kill(pid, SIGSYS);
697 	}
698 	if (vtable[SCRIPT].v_access&CHANGED) {
699 		vtable[SCRIPT].v_access &= ~CHANGED;
700 		setscript();
701 		/*
702 		 * So that "set record=blah script" doesn't
703 		 *  cause two transactions to occur.
704 		 */
705 		if (vtable[RECORD].v_access&CHANGED)
706 			vtable[RECORD].v_access &= ~CHANGED;
707 	}
708 	if (vtable[RECORD].v_access&CHANGED) {
709 		vtable[RECORD].v_access &= ~CHANGED;
710 		if (boolean(value(SCRIPT)))
711 			setscript();
712 	}
713 	if (vtable[TAND].v_access&CHANGED) {
714 		vtable[TAND].v_access &= ~CHANGED;
715 		if (boolean(value(TAND)))
716 			tandem("on");
717 		else
718 			tandem("off");
719 	}
720  	if (vtable[LECHO].v_access&CHANGED) {
721  		vtable[LECHO].v_access &= ~CHANGED;
722  		HD = boolean(value(LECHO));
723  	}
724 	if (vtable[PARITY].v_access&CHANGED) {
725 		vtable[PARITY].v_access &= ~CHANGED;
726 		setparity();
727 	}
728 }
729 
730 /*
731  * Turn tandem mode on or off for remote tty.
732  */
733 tandem(option)
734 	char *option;
735 {
736 	struct sgttyb rmtty;
737 
738 	ioctl(FD, TIOCGETP, &rmtty);
739 	if (strcmp(option,"on") == 0) {
740 		rmtty.sg_flags |= TANDEM;
741 		arg.sg_flags |= TANDEM;
742 	} else {
743 		rmtty.sg_flags &= ~TANDEM;
744 		arg.sg_flags &= ~TANDEM;
745 	}
746 	ioctl(FD, TIOCSETP, &rmtty);
747 	ioctl(0,  TIOCSETP, &arg);
748 }
749 
750 /*
751  * Send a break.
752  */
753 genbrk()
754 {
755 
756 	ioctl(FD, TIOCSBRK, NULL);
757 	sleep(1);
758 	ioctl(FD, TIOCCBRK, NULL);
759 }
760 
761 /*
762  * Suspend tip
763  */
764 suspend(c)
765 	char c;
766 {
767 
768 	unraw();
769 	kill(c == CTRL(y) ? getpid() : 0, SIGTSTP);
770 	raw();
771 }
772 
773 /*
774  *	expand a file name if it includes shell meta characters
775  */
776 
777 char *
778 expand(name)
779 	char name[];
780 {
781 	static char xname[BUFSIZ];
782 	char cmdbuf[BUFSIZ];
783 	register int pid, l, rc;
784 	register char *cp, *Shell;
785 	int s, pivec[2], (*sigint)();
786 
787 	if (!anyof(name, "~{[*?$`'\"\\"))
788 		return(name);
789 	/* sigint = signal(SIGINT, SIG_IGN); */
790 	if (pipe(pivec) < 0) {
791 		perror("pipe");
792 		/* signal(SIGINT, sigint) */
793 		return(name);
794 	}
795 	sprintf(cmdbuf, "echo %s", name);
796 	if ((pid = vfork()) == 0) {
797 		Shell = value(SHELL);
798 		if (Shell == NOSTR)
799 			Shell = "/bin/sh";
800 		close(pivec[0]);
801 		close(1);
802 		dup(pivec[1]);
803 		close(pivec[1]);
804 		close(2);
805 		execl(Shell, Shell, "-c", cmdbuf, 0);
806 		_exit(1);
807 	}
808 	if (pid == -1) {
809 		perror("fork");
810 		close(pivec[0]);
811 		close(pivec[1]);
812 		return(NOSTR);
813 	}
814 	close(pivec[1]);
815 	l = read(pivec[0], xname, BUFSIZ);
816 	close(pivec[0]);
817 	while (wait(&s) != pid);
818 		;
819 	s &= 0377;
820 	if (s != 0 && s != SIGPIPE) {
821 		fprintf(stderr, "\"Echo\" failed\n");
822 		return(NOSTR);
823 	}
824 	if (l < 0) {
825 		perror("read");
826 		return(NOSTR);
827 	}
828 	if (l == 0) {
829 		fprintf(stderr, "\"%s\": No match\n", name);
830 		return(NOSTR);
831 	}
832 	if (l == BUFSIZ) {
833 		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
834 		return(NOSTR);
835 	}
836 	xname[l] = 0;
837 	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
838 		;
839 	*++cp = '\0';
840 	return(xname);
841 }
842 
843 /*
844  * Are any of the characters in the two strings the same?
845  */
846 
847 anyof(s1, s2)
848 	register char *s1, *s2;
849 {
850 	register int c;
851 
852 	while (c = *s1++)
853 		if (any(c, s2))
854 			return(1);
855 	return(0);
856 }
857