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