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