xref: /netbsd-src/usr.bin/tip/cmds.c (revision 0b9f50897e9a9c6709320fafb4c3787fddcc0a45)
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[] = "from: @(#)cmds.c	5.15 (Berkeley) 3/4/91";*/
36 static char rcsid[] = "$Id: cmds.c,v 1.2 1993/08/01 18:06:43 mycroft Exp $";
37 #endif /* not lint */
38 
39 #include "tip.h"
40 #include "pathnames.h"
41 
42 /*
43  * tip
44  *
45  * miscellaneous commands
46  */
47 
48 int	quant[] = { 60, 60, 24 };
49 
50 char	null = '\0';
51 char	*sep[] = { "second", "minute", "hour" };
52 static char *argv[10];		/* argument vector for take and put */
53 
54 void	timeout();		/* timeout function called on alarm */
55 void	stopsnd();		/* SIGINT handler during file transfers */
56 void	intcopy();		/* interrupt routine for file transfers */
57 
58 /*
59  * FTP - remote ==> local
60  *  get a file from the remote host
61  */
62 getfl(c)
63 	char c;
64 {
65 	char buf[256], *cp, *expand();
66 
67 	putchar(c);
68 	/*
69 	 * get the UNIX receiving file's name
70 	 */
71 	if (prompt("Local file name? ", copyname))
72 		return;
73 	cp = expand(copyname);
74 	if ((sfd = creat(cp, 0666)) < 0) {
75 		printf("\r\n%s: cannot creat\r\n", copyname);
76 		return;
77 	}
78 
79 	/*
80 	 * collect parameters
81 	 */
82 	if (prompt("List command for remote system? ", buf)) {
83 		unlink(copyname);
84 		return;
85 	}
86 	transfer(buf, sfd, value(EOFREAD));
87 }
88 
89 /*
90  * Cu-like take command
91  */
92 cu_take(cc)
93 	char cc;
94 {
95 	int fd, argc;
96 	char line[BUFSIZ], *expand(), *cp;
97 
98 	if (prompt("[take] ", copyname))
99 		return;
100 	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
101 		printf("usage: <take> from [to]\r\n");
102 		return;
103 	}
104 	if (argc == 1)
105 		argv[1] = argv[0];
106 	cp = expand(argv[1]);
107 	if ((fd = creat(cp, 0666)) < 0) {
108 		printf("\r\n%s: cannot create\r\n", argv[1]);
109 		return;
110 	}
111 	sprintf(line, "cat %s;echo \01", argv[0]);
112 	transfer(line, fd, "\01");
113 }
114 
115 static	jmp_buf intbuf;
116 /*
117  * Bulk transfer routine --
118  *  used by getfl(), cu_take(), and pipefile()
119  */
120 transfer(buf, fd, eofchars)
121 	char *buf, *eofchars;
122 {
123 	register int ct;
124 	char c, buffer[BUFSIZ];
125 	register char *p = buffer;
126 	register int cnt, eof;
127 	time_t start;
128 	sig_t f;
129 
130 	pwrite(FD, buf, size(buf));
131 	quit = 0;
132 	kill(pid, SIGIOT);
133 	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
134 
135 	/*
136 	 * finish command
137 	 */
138 	pwrite(FD, "\r", 1);
139 	do
140 		read(FD, &c, 1);
141 	while ((c&0177) != '\n');
142 	ioctl(0, TIOCSETC, &defchars);
143 
144 	(void) setjmp(intbuf);
145 	f = signal(SIGINT, intcopy);
146 	start = time(0);
147 	for (ct = 0; !quit;) {
148 		eof = read(FD, &c, 1) <= 0;
149 		c &= 0177;
150 		if (quit)
151 			continue;
152 		if (eof || any(c, eofchars))
153 			break;
154 		if (c == 0)
155 			continue;	/* ignore nulls */
156 		if (c == '\r')
157 			continue;
158 		*p++ = c;
159 
160 		if (c == '\n' && boolean(value(VERBOSE)))
161 			printf("\r%d", ++ct);
162 		if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
163 			if (write(fd, buffer, cnt) != cnt) {
164 				printf("\r\nwrite error\r\n");
165 				quit = 1;
166 			}
167 			p = buffer;
168 		}
169 	}
170 	if (cnt = (p-buffer))
171 		if (write(fd, buffer, cnt) != cnt)
172 			printf("\r\nwrite error\r\n");
173 
174 	if (boolean(value(VERBOSE)))
175 		prtime(" lines transferred in ", time(0)-start);
176 	ioctl(0, TIOCSETC, &tchars);
177 	write(fildes[1], (char *)&ccc, 1);
178 	signal(SIGINT, f);
179 	close(fd);
180 }
181 
182 /*
183  * FTP - remote ==> local process
184  *   send remote input to local process via pipe
185  */
186 pipefile()
187 {
188 	int cpid, pdes[2];
189 	char buf[256];
190 	int status, p;
191 	extern int errno;
192 
193 	if (prompt("Local command? ", buf))
194 		return;
195 
196 	if (pipe(pdes)) {
197 		printf("can't establish pipe\r\n");
198 		return;
199 	}
200 
201 	if ((cpid = fork()) < 0) {
202 		printf("can't fork!\r\n");
203 		return;
204 	} else if (cpid) {
205 		if (prompt("List command for remote system? ", buf)) {
206 			close(pdes[0]), close(pdes[1]);
207 			kill (cpid, SIGKILL);
208 		} else {
209 			close(pdes[0]);
210 			signal(SIGPIPE, intcopy);
211 			transfer(buf, pdes[1], value(EOFREAD));
212 			signal(SIGPIPE, SIG_DFL);
213 			while ((p = wait(&status)) > 0 && p != cpid)
214 				;
215 		}
216 	} else {
217 		register int f;
218 
219 		dup2(pdes[0], 0);
220 		close(pdes[0]);
221 		for (f = 3; f < 20; f++)
222 			close(f);
223 		execute(buf);
224 		printf("can't execl!\r\n");
225 		exit(0);
226 	}
227 }
228 
229 /*
230  * Interrupt service routine for FTP
231  */
232 void
233 stopsnd()
234 {
235 
236 	stop = 1;
237 	signal(SIGINT, SIG_IGN);
238 }
239 
240 /*
241  * FTP - local ==> remote
242  *  send local file to remote host
243  *  terminate transmission with pseudo EOF sequence
244  */
245 sendfile(cc)
246 	char cc;
247 {
248 	FILE *fd;
249 	char *fnamex;
250 	char *expand();
251 
252 	putchar(cc);
253 	/*
254 	 * get file name
255 	 */
256 	if (prompt("Local file name? ", fname))
257 		return;
258 
259 	/*
260 	 * look up file
261 	 */
262 	fnamex = expand(fname);
263 	if ((fd = fopen(fnamex, "r")) == NULL) {
264 		printf("%s: cannot open\r\n", fname);
265 		return;
266 	}
267 	transmit(fd, value(EOFWRITE), NULL);
268 	if (!boolean(value(ECHOCHECK))) {
269 		struct sgttyb buf;
270 
271 		ioctl(FD, TIOCGETP, &buf);	/* this does a */
272 		ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
273 	}
274 }
275 
276 /*
277  * Bulk transfer routine to remote host --
278  *   used by sendfile() and cu_put()
279  */
280 transmit(fd, eofchars, command)
281 	FILE *fd;
282 	char *eofchars, *command;
283 {
284 	char *pc, lastc;
285 	int c, ccount, lcount;
286 	time_t start_t, stop_t;
287 	sig_t f;
288 
289 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
290 	stop = 0;
291 	f = signal(SIGINT, stopsnd);
292 	ioctl(0, TIOCSETC, &defchars);
293 	read(repdes[0], (char *)&ccc, 1);
294 	if (command != NULL) {
295 		for (pc = command; *pc; pc++)
296 			send(*pc);
297 		if (boolean(value(ECHOCHECK)))
298 			read(FD, (char *)&c, 1);	/* trailing \n */
299 		else {
300 			struct sgttyb buf;
301 
302 			ioctl(FD, TIOCGETP, &buf);	/* this does a */
303 			ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
304 			sleep(5); /* wait for remote stty to take effect */
305 		}
306 	}
307 	lcount = 0;
308 	lastc = '\0';
309 	start_t = time(0);
310 	while (1) {
311 		ccount = 0;
312 		do {
313 			c = getc(fd);
314 			if (stop)
315 				goto out;
316 			if (c == EOF)
317 				goto out;
318 			if (c == 0177 && !boolean(value(RAWFTP)))
319 				continue;
320 			lastc = c;
321 			if (c < 040) {
322 				if (c == '\n') {
323 					if (!boolean(value(RAWFTP)))
324 						c = '\r';
325 				}
326 				else if (c == '\t') {
327 					if (!boolean(value(RAWFTP))) {
328 						if (boolean(value(TABEXPAND))) {
329 							send(' ');
330 							while ((++ccount % 8) != 0)
331 								send(' ');
332 							continue;
333 						}
334 					}
335 				} else
336 					if (!boolean(value(RAWFTP)))
337 						continue;
338 			}
339 			send(c);
340 		} while (c != '\r' && !boolean(value(RAWFTP)));
341 		if (boolean(value(VERBOSE)))
342 			printf("\r%d", ++lcount);
343 		if (boolean(value(ECHOCHECK))) {
344 			timedout = 0;
345 			alarm((int)value(ETIMEOUT));
346 			do {	/* wait for prompt */
347 				read(FD, (char *)&c, 1);
348 				if (timedout || stop) {
349 					if (timedout)
350 						printf("\r\ntimed out at eol\r\n");
351 					alarm(0);
352 					goto out;
353 				}
354 			} while ((c&0177) != character(value(PROMPT)));
355 			alarm(0);
356 		}
357 	}
358 out:
359 	if (lastc != '\n' && !boolean(value(RAWFTP)))
360 		send('\r');
361 	for (pc = eofchars; *pc; pc++)
362 		send(*pc);
363 	stop_t = time(0);
364 	fclose(fd);
365 	signal(SIGINT, f);
366 	if (boolean(value(VERBOSE)))
367 		if (boolean(value(RAWFTP)))
368 			prtime(" chars transferred in ", stop_t-start_t);
369 		else
370 			prtime(" lines transferred in ", stop_t-start_t);
371 	write(fildes[1], (char *)&ccc, 1);
372 	ioctl(0, TIOCSETC, &tchars);
373 }
374 
375 /*
376  * Cu-like put command
377  */
378 cu_put(cc)
379 	char cc;
380 {
381 	FILE *fd;
382 	char line[BUFSIZ];
383 	int argc;
384 	char *expand();
385 	char *copynamex;
386 
387 	if (prompt("[put] ", copyname))
388 		return;
389 	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
390 		printf("usage: <put> from [to]\r\n");
391 		return;
392 	}
393 	if (argc == 1)
394 		argv[1] = argv[0];
395 	copynamex = expand(argv[0]);
396 	if ((fd = fopen(copynamex, "r")) == NULL) {
397 		printf("%s: cannot open\r\n", copynamex);
398 		return;
399 	}
400 	if (boolean(value(ECHOCHECK)))
401 		sprintf(line, "cat>%s\r", argv[1]);
402 	else
403 		sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
404 	transmit(fd, "\04", line);
405 }
406 
407 /*
408  * FTP - send single character
409  *  wait for echo & handle timeout
410  */
411 send(c)
412 	char c;
413 {
414 	char cc;
415 	int retry = 0;
416 
417 	cc = c;
418 	pwrite(FD, &cc, 1);
419 #ifdef notdef
420 	if (number(value(CDELAY)) > 0 && c != '\r')
421 		nap(number(value(CDELAY)));
422 #endif
423 	if (!boolean(value(ECHOCHECK))) {
424 #ifdef notdef
425 		if (number(value(LDELAY)) > 0 && c == '\r')
426 			nap(number(value(LDELAY)));
427 #endif
428 		return;
429 	}
430 tryagain:
431 	timedout = 0;
432 	alarm((int)value(ETIMEOUT));
433 	read(FD, &cc, 1);
434 	alarm(0);
435 	if (timedout) {
436 		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
437 		if (retry++ > 3)
438 			return;
439 		pwrite(FD, &null, 1); /* poke it */
440 		goto tryagain;
441 	}
442 }
443 
444 void
445 timeout()
446 {
447 	signal(SIGALRM, timeout);
448 	timedout = 1;
449 }
450 
451 /*
452  * Stolen from consh() -- puts a remote file on the output of a local command.
453  *	Identical to consh() except for where stdout goes.
454  */
455 pipeout(c)
456 {
457 	char buf[256];
458 	int cpid, status, p;
459 	time_t start;
460 
461 	putchar(c);
462 	if (prompt("Local command? ", buf))
463 		return;
464 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
465 	signal(SIGINT, SIG_IGN);
466 	signal(SIGQUIT, SIG_IGN);
467 	ioctl(0, TIOCSETC, &defchars);
468 	read(repdes[0], (char *)&ccc, 1);
469 	/*
470 	 * Set up file descriptors in the child and
471 	 *  let it go...
472 	 */
473 	if ((cpid = fork()) < 0)
474 		printf("can't fork!\r\n");
475 	else if (cpid) {
476 		start = time(0);
477 		while ((p = wait(&status)) > 0 && p != cpid)
478 			;
479 	} else {
480 		register int i;
481 
482 		dup2(FD, 1);
483 		for (i = 3; i < 20; i++)
484 			close(i);
485 		signal(SIGINT, SIG_DFL);
486 		signal(SIGQUIT, SIG_DFL);
487 		execute(buf);
488 		printf("can't find `%s'\r\n", buf);
489 		exit(0);
490 	}
491 	if (boolean(value(VERBOSE)))
492 		prtime("away for ", time(0)-start);
493 	write(fildes[1], (char *)&ccc, 1);
494 	ioctl(0, TIOCSETC, &tchars);
495 	signal(SIGINT, SIG_DFL);
496 	signal(SIGQUIT, SIG_DFL);
497 }
498 
499 #ifdef CONNECT
500 /*
501  * Fork a program with:
502  *  0 <-> remote tty in
503  *  1 <-> remote tty out
504  *  2 <-> local tty out
505  */
506 consh(c)
507 {
508 	char buf[256];
509 	int cpid, status, p;
510 	time_t start;
511 
512 	putchar(c);
513 	if (prompt("Local command? ", buf))
514 		return;
515 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
516 	signal(SIGINT, SIG_IGN);
517 	signal(SIGQUIT, SIG_IGN);
518 	ioctl(0, TIOCSETC, &defchars);
519 	read(repdes[0], (char *)&ccc, 1);
520 	/*
521 	 * Set up file descriptors in the child and
522 	 *  let it go...
523 	 */
524 	if ((cpid = fork()) < 0)
525 		printf("can't fork!\r\n");
526 	else if (cpid) {
527 		start = time(0);
528 		while ((p = wait(&status)) > 0 && p != cpid)
529 			;
530 	} else {
531 		register int i;
532 
533 		dup2(1, 2);
534 		dup2(FD, 0);
535 		dup2(0, 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 	ioctl(0, TIOCSETC, &tchars);
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 sgttyb rmtty;
768 
769 	ioctl(FD, TIOCGETP, &rmtty);
770 	if (strcmp(option,"on") == 0) {
771 		rmtty.sg_flags |= TANDEM;
772 		arg.sg_flags |= TANDEM;
773 	} else {
774 		rmtty.sg_flags &= ~TANDEM;
775 		arg.sg_flags &= ~TANDEM;
776 	}
777 	ioctl(FD, TIOCSETP, &rmtty);
778 	ioctl(0,  TIOCSETP, &arg);
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