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