xref: /netbsd-src/usr.bin/tip/cmds.c (revision 1f2744e6e4915c9da2a3f980279398c4cf7d5e6d)
1 /*	$NetBSD: cmds.c,v 1.4 1994/12/24 17:56:23 cgd 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.4 1994/12/24 17:56:23 cgd 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&0177) != '\n');
148 	ioctl(0, TIOCSETC, &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 &= 0177;
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 	ioctl(0, TIOCSETC, &tchars);
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 		struct sgttyb buf;
276 
277 		ioctl(FD, TIOCGETP, &buf);	/* this does a */
278 		ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
279 	}
280 }
281 
282 /*
283  * Bulk transfer routine to remote host --
284  *   used by sendfile() and cu_put()
285  */
286 transmit(fd, eofchars, command)
287 	FILE *fd;
288 	char *eofchars, *command;
289 {
290 	char *pc, lastc;
291 	int c, ccount, lcount;
292 	time_t start_t, stop_t;
293 	sig_t f;
294 
295 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
296 	stop = 0;
297 	f = signal(SIGINT, stopsnd);
298 	ioctl(0, TIOCSETC, &defchars);
299 	read(repdes[0], (char *)&ccc, 1);
300 	if (command != NULL) {
301 		for (pc = command; *pc; pc++)
302 			send(*pc);
303 		if (boolean(value(ECHOCHECK)))
304 			read(FD, (char *)&c, 1);	/* trailing \n */
305 		else {
306 			struct sgttyb buf;
307 
308 			ioctl(FD, TIOCGETP, &buf);	/* this does a */
309 			ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
310 			sleep(5); /* wait for remote stty to take effect */
311 		}
312 	}
313 	lcount = 0;
314 	lastc = '\0';
315 	start_t = time(0);
316 	while (1) {
317 		ccount = 0;
318 		do {
319 			c = getc(fd);
320 			if (stop)
321 				goto out;
322 			if (c == EOF)
323 				goto out;
324 			if (c == 0177 && !boolean(value(RAWFTP)))
325 				continue;
326 			lastc = c;
327 			if (c < 040) {
328 				if (c == '\n') {
329 					if (!boolean(value(RAWFTP)))
330 						c = '\r';
331 				}
332 				else if (c == '\t') {
333 					if (!boolean(value(RAWFTP))) {
334 						if (boolean(value(TABEXPAND))) {
335 							send(' ');
336 							while ((++ccount % 8) != 0)
337 								send(' ');
338 							continue;
339 						}
340 					}
341 				} else
342 					if (!boolean(value(RAWFTP)))
343 						continue;
344 			}
345 			send(c);
346 		} while (c != '\r' && !boolean(value(RAWFTP)));
347 		if (boolean(value(VERBOSE)))
348 			printf("\r%d", ++lcount);
349 		if (boolean(value(ECHOCHECK))) {
350 			timedout = 0;
351 			alarm((long)value(ETIMEOUT));
352 			do {	/* wait for prompt */
353 				read(FD, (char *)&c, 1);
354 				if (timedout || stop) {
355 					if (timedout)
356 						printf("\r\ntimed out at eol\r\n");
357 					alarm(0);
358 					goto out;
359 				}
360 			} while ((c&0177) != character(value(PROMPT)));
361 			alarm(0);
362 		}
363 	}
364 out:
365 	if (lastc != '\n' && !boolean(value(RAWFTP)))
366 		send('\r');
367 	for (pc = eofchars; *pc; pc++)
368 		send(*pc);
369 	stop_t = time(0);
370 	fclose(fd);
371 	signal(SIGINT, f);
372 	if (boolean(value(VERBOSE)))
373 		if (boolean(value(RAWFTP)))
374 			prtime(" chars transferred in ", stop_t-start_t);
375 		else
376 			prtime(" lines transferred in ", stop_t-start_t);
377 	write(fildes[1], (char *)&ccc, 1);
378 	ioctl(0, TIOCSETC, &tchars);
379 }
380 
381 /*
382  * Cu-like put command
383  */
384 cu_put(cc)
385 	char cc;
386 {
387 	FILE *fd;
388 	char line[BUFSIZ];
389 	int argc;
390 	char *expand();
391 	char *copynamex;
392 
393 	if (prompt("[put] ", copyname))
394 		return;
395 	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
396 		printf("usage: <put> from [to]\r\n");
397 		return;
398 	}
399 	if (argc == 1)
400 		argv[1] = argv[0];
401 	copynamex = expand(argv[0]);
402 	if ((fd = fopen(copynamex, "r")) == NULL) {
403 		printf("%s: cannot open\r\n", copynamex);
404 		return;
405 	}
406 	if (boolean(value(ECHOCHECK)))
407 		sprintf(line, "cat>%s\r", argv[1]);
408 	else
409 		sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
410 	transmit(fd, "\04", line);
411 }
412 
413 /*
414  * FTP - send single character
415  *  wait for echo & handle timeout
416  */
417 send(c)
418 	char c;
419 {
420 	char cc;
421 	int retry = 0;
422 
423 	cc = c;
424 	pwrite(FD, &cc, 1);
425 #ifdef notdef
426 	if (number(value(CDELAY)) > 0 && c != '\r')
427 		nap(number(value(CDELAY)));
428 #endif
429 	if (!boolean(value(ECHOCHECK))) {
430 #ifdef notdef
431 		if (number(value(LDELAY)) > 0 && c == '\r')
432 			nap(number(value(LDELAY)));
433 #endif
434 		return;
435 	}
436 tryagain:
437 	timedout = 0;
438 	alarm((long)value(ETIMEOUT));
439 	read(FD, &cc, 1);
440 	alarm(0);
441 	if (timedout) {
442 		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
443 		if (retry++ > 3)
444 			return;
445 		pwrite(FD, &null, 1); /* poke it */
446 		goto tryagain;
447 	}
448 }
449 
450 void
451 timeout()
452 {
453 	signal(SIGALRM, timeout);
454 	timedout = 1;
455 }
456 
457 /*
458  * Stolen from consh() -- puts a remote file on the output of a local command.
459  *	Identical to consh() except for where stdout goes.
460  */
461 pipeout(c)
462 {
463 	char buf[256];
464 	int cpid, status, p;
465 	time_t start;
466 
467 	putchar(c);
468 	if (prompt("Local command? ", buf))
469 		return;
470 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
471 	signal(SIGINT, SIG_IGN);
472 	signal(SIGQUIT, SIG_IGN);
473 	ioctl(0, TIOCSETC, &defchars);
474 	read(repdes[0], (char *)&ccc, 1);
475 	/*
476 	 * Set up file descriptors in the child and
477 	 *  let it go...
478 	 */
479 	if ((cpid = fork()) < 0)
480 		printf("can't fork!\r\n");
481 	else if (cpid) {
482 		start = time(0);
483 		while ((p = wait(&status)) > 0 && p != cpid)
484 			;
485 	} else {
486 		register int i;
487 
488 		dup2(FD, 1);
489 		for (i = 3; i < 20; i++)
490 			close(i);
491 		signal(SIGINT, SIG_DFL);
492 		signal(SIGQUIT, SIG_DFL);
493 		execute(buf);
494 		printf("can't find `%s'\r\n", buf);
495 		exit(0);
496 	}
497 	if (boolean(value(VERBOSE)))
498 		prtime("away for ", time(0)-start);
499 	write(fildes[1], (char *)&ccc, 1);
500 	ioctl(0, TIOCSETC, &tchars);
501 	signal(SIGINT, SIG_DFL);
502 	signal(SIGQUIT, SIG_DFL);
503 }
504 
505 #ifdef CONNECT
506 /*
507  * Fork a program with:
508  *  0 <-> remote tty in
509  *  1 <-> remote tty out
510  *  2 <-> local tty out
511  */
512 consh(c)
513 {
514 	char buf[256];
515 	int cpid, status, p;
516 	time_t start;
517 
518 	putchar(c);
519 	if (prompt("Local command? ", buf))
520 		return;
521 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
522 	signal(SIGINT, SIG_IGN);
523 	signal(SIGQUIT, SIG_IGN);
524 	ioctl(0, TIOCSETC, &defchars);
525 	read(repdes[0], (char *)&ccc, 1);
526 	/*
527 	 * Set up file descriptors in the child and
528 	 *  let it go...
529 	 */
530 	if ((cpid = fork()) < 0)
531 		printf("can't fork!\r\n");
532 	else if (cpid) {
533 		start = time(0);
534 		while ((p = wait(&status)) > 0 && p != cpid)
535 			;
536 	} else {
537 		register int i;
538 
539 		dup2(FD, 0);
540 		dup2(3, 1);
541 		for (i = 3; i < 20; i++)
542 			close(i);
543 		signal(SIGINT, SIG_DFL);
544 		signal(SIGQUIT, SIG_DFL);
545 		execute(buf);
546 		printf("can't find `%s'\r\n", buf);
547 		exit(0);
548 	}
549 	if (boolean(value(VERBOSE)))
550 		prtime("away for ", time(0)-start);
551 	write(fildes[1], (char *)&ccc, 1);
552 	ioctl(0, TIOCSETC, &tchars);
553 	signal(SIGINT, SIG_DFL);
554 	signal(SIGQUIT, SIG_DFL);
555 }
556 #endif
557 
558 /*
559  * Escape to local shell
560  */
561 shell()
562 {
563 	int shpid, status;
564 	extern char **environ;
565 	char *cp;
566 
567 	printf("[sh]\r\n");
568 	signal(SIGINT, SIG_IGN);
569 	signal(SIGQUIT, SIG_IGN);
570 	unraw();
571 	if (shpid = fork()) {
572 		while (shpid != wait(&status));
573 		raw();
574 		printf("\r\n!\r\n");
575 		signal(SIGINT, SIG_DFL);
576 		signal(SIGQUIT, SIG_DFL);
577 		return;
578 	} else {
579 		signal(SIGQUIT, SIG_DFL);
580 		signal(SIGINT, SIG_DFL);
581 		if ((cp = rindex(value(SHELL), '/')) == NULL)
582 			cp = value(SHELL);
583 		else
584 			cp++;
585 		shell_uid();
586 		execl(value(SHELL), cp, 0);
587 		printf("\r\ncan't execl!\r\n");
588 		exit(1);
589 	}
590 }
591 
592 /*
593  * TIPIN portion of scripting
594  *   initiate the conversation with TIPOUT
595  */
596 setscript()
597 {
598 	char c;
599 	/*
600 	 * enable TIPOUT side for dialogue
601 	 */
602 	kill(pid, SIGEMT);
603 	if (boolean(value(SCRIPT)))
604 		write(fildes[1], value(RECORD), size(value(RECORD)));
605 	write(fildes[1], "\n", 1);
606 	/*
607 	 * wait for TIPOUT to finish
608 	 */
609 	read(repdes[0], &c, 1);
610 	if (c == 'n')
611 		printf("can't create %s\r\n", value(RECORD));
612 }
613 
614 /*
615  * Change current working directory of
616  *   local portion of tip
617  */
618 chdirectory()
619 {
620 	char dirname[80];
621 	register char *cp = dirname;
622 
623 	if (prompt("[cd] ", dirname)) {
624 		if (stoprompt)
625 			return;
626 		cp = value(HOME);
627 	}
628 	if (chdir(cp) < 0)
629 		printf("%s: bad directory\r\n", cp);
630 	printf("!\r\n");
631 }
632 
633 tipabort(msg)
634 	char *msg;
635 {
636 
637 	kill(pid, SIGTERM);
638 	disconnect(msg);
639 	if (msg != NOSTR)
640 		printf("\r\n%s", msg);
641 	printf("\r\n[EOT]\r\n");
642 	daemon_uid();
643 	(void)uu_unlock(uucplock);
644 	unraw();
645 	exit(0);
646 }
647 
648 finish()
649 {
650 	char *dismsg;
651 
652 	if ((dismsg = value(DISCONNECT)) != NOSTR) {
653 		write(FD, dismsg, strlen(dismsg));
654 		sleep(5);
655 	}
656 	tipabort(NOSTR);
657 }
658 
659 void
660 intcopy()
661 {
662 	raw();
663 	quit = 1;
664 	longjmp(intbuf, 1);
665 }
666 
667 execute(s)
668 	char *s;
669 {
670 	register char *cp;
671 
672 	if ((cp = rindex(value(SHELL), '/')) == NULL)
673 		cp = value(SHELL);
674 	else
675 		cp++;
676 	shell_uid();
677 	execl(value(SHELL), cp, "-c", s, 0);
678 }
679 
680 args(buf, a)
681 	char *buf, *a[];
682 {
683 	register char *p = buf, *start;
684 	register char **parg = a;
685 	register int n = 0;
686 
687 	do {
688 		while (*p && (*p == ' ' || *p == '\t'))
689 			p++;
690 		start = p;
691 		if (*p)
692 			*parg = p;
693 		while (*p && (*p != ' ' && *p != '\t'))
694 			p++;
695 		if (p != start)
696 			parg++, n++;
697 		if (*p)
698 			*p++ = '\0';
699 	} while (*p);
700 
701 	return(n);
702 }
703 
704 prtime(s, a)
705 	char *s;
706 	time_t a;
707 {
708 	register i;
709 	int nums[3];
710 
711 	for (i = 0; i < 3; i++) {
712 		nums[i] = (int)(a % quant[i]);
713 		a /= quant[i];
714 	}
715 	printf("%s", s);
716 	while (--i >= 0)
717 		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
718 			printf("%d %s%c ", nums[i], sep[i],
719 				nums[i] == 1 ? '\0' : 's');
720 	printf("\r\n!\r\n");
721 }
722 
723 variable()
724 {
725 	char	buf[256];
726 
727 	if (prompt("[set] ", buf))
728 		return;
729 	vlex(buf);
730 	if (vtable[BEAUTIFY].v_access&CHANGED) {
731 		vtable[BEAUTIFY].v_access &= ~CHANGED;
732 		kill(pid, SIGSYS);
733 	}
734 	if (vtable[SCRIPT].v_access&CHANGED) {
735 		vtable[SCRIPT].v_access &= ~CHANGED;
736 		setscript();
737 		/*
738 		 * So that "set record=blah script" doesn't
739 		 *  cause two transactions to occur.
740 		 */
741 		if (vtable[RECORD].v_access&CHANGED)
742 			vtable[RECORD].v_access &= ~CHANGED;
743 	}
744 	if (vtable[RECORD].v_access&CHANGED) {
745 		vtable[RECORD].v_access &= ~CHANGED;
746 		if (boolean(value(SCRIPT)))
747 			setscript();
748 	}
749 	if (vtable[TAND].v_access&CHANGED) {
750 		vtable[TAND].v_access &= ~CHANGED;
751 		if (boolean(value(TAND)))
752 			tandem("on");
753 		else
754 			tandem("off");
755 	}
756  	if (vtable[LECHO].v_access&CHANGED) {
757  		vtable[LECHO].v_access &= ~CHANGED;
758  		HD = boolean(value(LECHO));
759  	}
760 	if (vtable[PARITY].v_access&CHANGED) {
761 		vtable[PARITY].v_access &= ~CHANGED;
762 		setparity();
763 	}
764 }
765 
766 /*
767  * Turn tandem mode on or off for remote tty.
768  */
769 tandem(option)
770 	char *option;
771 {
772 	struct sgttyb rmtty;
773 
774 	ioctl(FD, TIOCGETP, &rmtty);
775 	if (strcmp(option,"on") == 0) {
776 		rmtty.sg_flags |= TANDEM;
777 		arg.sg_flags |= TANDEM;
778 	} else {
779 		rmtty.sg_flags &= ~TANDEM;
780 		arg.sg_flags &= ~TANDEM;
781 	}
782 	ioctl(FD, TIOCSETP, &rmtty);
783 	ioctl(0,  TIOCSETP, &arg);
784 }
785 
786 /*
787  * Send a break.
788  */
789 genbrk()
790 {
791 
792 	ioctl(FD, TIOCSBRK, NULL);
793 	sleep(1);
794 	ioctl(FD, TIOCCBRK, NULL);
795 }
796 
797 /*
798  * Suspend tip
799  */
800 suspend(c)
801 	char c;
802 {
803 
804 	unraw();
805 	kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
806 	raw();
807 }
808 
809 /*
810  *	expand a file name if it includes shell meta characters
811  */
812 
813 char *
814 expand(name)
815 	char name[];
816 {
817 	static char xname[BUFSIZ];
818 	char cmdbuf[BUFSIZ];
819 	register int pid, l, rc;
820 	register char *cp, *Shell;
821 	int s, pivec[2], (*sigint)();
822 
823 	if (!anyof(name, "~{[*?$`'\"\\"))
824 		return(name);
825 	/* sigint = signal(SIGINT, SIG_IGN); */
826 	if (pipe(pivec) < 0) {
827 		perror("pipe");
828 		/* signal(SIGINT, sigint) */
829 		return(name);
830 	}
831 	sprintf(cmdbuf, "echo %s", name);
832 	if ((pid = vfork()) == 0) {
833 		Shell = value(SHELL);
834 		if (Shell == NOSTR)
835 			Shell = _PATH_BSHELL;
836 		close(pivec[0]);
837 		close(1);
838 		dup(pivec[1]);
839 		close(pivec[1]);
840 		close(2);
841 		shell_uid();
842 		execl(Shell, Shell, "-c", cmdbuf, 0);
843 		_exit(1);
844 	}
845 	if (pid == -1) {
846 		perror("fork");
847 		close(pivec[0]);
848 		close(pivec[1]);
849 		return(NOSTR);
850 	}
851 	close(pivec[1]);
852 	l = read(pivec[0], xname, BUFSIZ);
853 	close(pivec[0]);
854 	while (wait(&s) != pid);
855 		;
856 	s &= 0377;
857 	if (s != 0 && s != SIGPIPE) {
858 		fprintf(stderr, "\"Echo\" failed\n");
859 		return(NOSTR);
860 	}
861 	if (l < 0) {
862 		perror("read");
863 		return(NOSTR);
864 	}
865 	if (l == 0) {
866 		fprintf(stderr, "\"%s\": No match\n", name);
867 		return(NOSTR);
868 	}
869 	if (l == BUFSIZ) {
870 		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
871 		return(NOSTR);
872 	}
873 	xname[l] = 0;
874 	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
875 		;
876 	*++cp = '\0';
877 	return(xname);
878 }
879 
880 /*
881  * Are any of the characters in the two strings the same?
882  */
883 
884 anyof(s1, s2)
885 	register char *s1, *s2;
886 {
887 	register int c;
888 
889 	while (c = *s1++)
890 		if (any(c, s2))
891 			return(1);
892 	return(0);
893 }
894