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