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