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