cmds.c revision 7527
1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  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
35static char sccsid[] = "@(#)cmds.c	8.1 (Berkeley) 6/6/93";
36#endif /* not lint */
37
38#include "tipconf.h"
39#include "tip.h"
40#include "pathnames.h"
41
42#include <stdio.h>
43
44/*
45 * tip
46 *
47 * miscellaneous commands
48 */
49
50int	quant[] = { 60, 60, 24 };
51
52char	null = '\0';
53char	*sep[] = { "second", "minute", "hour" };
54static char *argv[10];		/* argument vector for take and put */
55
56void	timeout();		/* timeout function called on alarm */
57void	stopsnd();		/* SIGINT handler during file transfers */
58void	intcopy();		/* interrupt routine for file transfers */
59
60void
61usedefchars ()
62{
63#if HAVE_TERMIOS
64	int cnt;
65	struct termios ttermios;
66	ttermios = ctermios;
67	for (cnt = 0; cnt < NCCS; cnt++)
68		ttermios.c_cc [cnt] = otermios.c_cc [cnt];
69	tcsetattr (0, TCSANOW, &ttermios);
70#else
71	ioctl(0, TIOCSETC, &defchars);
72#endif
73}
74
75void
76usetchars ()
77{
78#if HAVE_TERMIOS
79	tcsetattr (0, TCSANOW, &ctermios);
80#else
81	ioctl(0, TIOCSETC, &tchars);
82#endif
83}
84
85void
86flush_remote ()
87{
88#ifdef TIOCFLUSH
89	int cmd = 0;
90	ioctl (FD, TIOCFLUSH, &cmd);
91#else
92	struct sgttyb buf;
93	ioctl (FD, TIOCGETP, &buf);	/* this does a */
94	ioctl (FD, TIOCSETP, &buf);	/*   wflushtty */
95#endif
96}
97
98/*
99 * FTP - remote ==> local
100 *  get a file from the remote host
101 */
102getfl(c)
103	char c;
104{
105	char buf[256], *cp, *expand();
106
107	putchar(c);
108	/*
109	 * get the UNIX receiving file's name
110	 */
111	if (prompt("Local file name? ", copyname))
112		return;
113	cp = expand(copyname);
114	if ((sfd = creat(cp, 0666)) < 0) {
115		printf("\r\n%s: cannot creat\r\n", copyname);
116		return;
117	}
118
119	/*
120	 * collect parameters
121	 */
122	if (prompt("List command for remote system? ", buf)) {
123		unlink(copyname);
124		return;
125	}
126	transfer(buf, sfd, value(EOFREAD));
127}
128
129/*
130 * Cu-like take command
131 */
132cu_take(cc)
133	char cc;
134{
135	int fd, argc;
136	char line[BUFSIZ], *expand(), *cp;
137
138	if (prompt("[take] ", copyname))
139		return;
140	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
141		printf("usage: <take> from [to]\r\n");
142		return;
143	}
144	if (argc == 1)
145		argv[1] = argv[0];
146	cp = expand(argv[1]);
147	if ((fd = creat(cp, 0666)) < 0) {
148		printf("\r\n%s: cannot create\r\n", argv[1]);
149		return;
150	}
151	(void)sprintf(line, "cat %s ; echo \"\" ; echo ___tip_end_of_file_marker___", argv[0]);
152	xfer(line, fd, "\n___tip_end_of_file_marker___\n");
153}
154
155extern jmp_buf intbuf;
156
157xfer(buf, fd, eofchars)
158	char *buf, *eofchars;
159{
160	register int ct;
161	char c, *match;
162	register int cnt, eof, v;
163	time_t start;
164	sig_t f;
165	char r;
166	FILE *ff;
167
168	v = boolean(value(VERBOSE));
169
170	if ((ff = fdopen (fd, "w")) == NULL) {
171		perror("file open");
172		return;
173	}
174	if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
175		if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
176			perror("file allocation");
177			(void)fclose(ff);
178			return;
179		}
180
181	pwrite(FD, buf, size(buf));
182	quit = 0;
183	kill(pid, SIGIOT);
184	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
185
186	/*
187	 * finish command
188	 */
189	r = '\r';
190	pwrite(FD, &r, 1);
191	do
192		read(FD, &c, 1);
193	while ((c&0177) != '\n');
194
195	usedefchars ();
196
197	(void) setjmp(intbuf);
198	f = signal(SIGINT, intcopy);
199	start = time(0);
200	match = eofchars;
201	for (ct = 0; !quit;) {
202		eof = read(FD, &c, 1) <= 0;
203		c &= 0177;
204		if (quit)
205			continue;
206		if (eof)
207			break;
208		if (c == 0)
209			continue;	/* ignore nulls */
210		if (c == '\r')
211			continue;
212		if (c != *match && match > eofchars) {
213			register char *p = eofchars;
214			while (p < match) {
215				if (*p == '\n'&& v)
216					(void)printf("\r%d", ++ct);
217				fputc(*p++, ff);
218			}
219			match = eofchars;
220		}
221		if (c == *match) {
222			if (*++match == '\0')
223				break;
224		} else {
225			if (c == '\n' && v)
226				(void)printf("\r%d", ++ct);
227			fputc(c, ff);
228		}
229	}
230	if (v)
231		prtime(" lines transferred in ", time(0)-start);
232	usetchars ();
233	write(fildes[1], (char *)&ccc, 1);
234	signal(SIGINT, f);
235	(void)fclose(ff);
236}
237
238static	jmp_buf intbuf;
239/*
240 * Bulk transfer routine --
241 *  used by getfl(), cu_take(), and pipefile()
242 */
243transfer(buf, fd, eofchars)
244	char *buf, *eofchars;
245{
246	register int ct;
247	char c, buffer[BUFSIZ];
248	register char *p = buffer;
249	register int cnt, eof, v;
250	time_t start;
251	sig_t f;
252	char r;
253	FILE *ff;
254
255	v = boolean(value(VERBOSE));
256
257	if ((ff = fdopen (fd, "w")) == NULL) {
258		perror("file open");
259		return;
260	}
261	if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
262		if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
263			perror("file allocation");
264			(void)fclose(ff);
265			return;
266		}
267
268	pwrite(FD, buf, size(buf));
269	quit = 0;
270	kill(pid, SIGIOT);
271	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
272
273	/*
274	 * finish command
275	 */
276	r = '\r';
277	pwrite(FD, &r, 1);
278	do
279		read(FD, &c, 1);
280	while ((c&0177) != '\n');
281	usedefchars ();
282	(void) setjmp(intbuf);
283	f = signal(SIGINT, intcopy);
284	start = time(0);
285	for (ct = 0; !quit;) {
286		eof = read(FD, &c, 1) <= 0;
287		c &= 0177;
288		if (quit)
289			continue;
290		if (eof || any(c, eofchars))
291			break;
292		if (c == 0)
293			continue;	/* ignore nulls */
294		if (c == '\r')
295			continue;
296		if (c == '\n' && v)
297			printf("\r%d", ++ct);
298		fputc(c, ff);
299	}
300	if (v)
301		prtime(" lines transferred in ", time(0)-start);
302	usetchars ();
303	write(fildes[1], (char *)&ccc, 1);
304	signal(SIGINT, f);
305	(void)fclose(ff);
306}
307
308/*
309 * FTP - remote ==> local process
310 *   send remote input to local process via pipe
311 */
312pipefile()
313{
314	int cpid, pdes[2];
315	char buf[256];
316	int status, p;
317	extern int errno;
318
319	if (prompt("Local command? ", buf))
320		return;
321
322	if (pipe(pdes)) {
323		printf("can't establish pipe\r\n");
324		return;
325	}
326
327	if ((cpid = fork()) < 0) {
328		printf("can't fork!\r\n");
329		return;
330	} else if (cpid) {
331		if (prompt("List command for remote system? ", buf)) {
332			close(pdes[0]), close(pdes[1]);
333			kill (cpid, SIGKILL);
334		} else {
335			close(pdes[0]);
336			signal(SIGPIPE, intcopy);
337			transfer(buf, pdes[1], value(EOFREAD));
338			signal(SIGPIPE, SIG_DFL);
339			while ((p = wait(&status)) > 0 && p != cpid)
340				;
341		}
342	} else {
343		register int f;
344
345		dup2(pdes[0], 0);
346		close(pdes[0]);
347		for (f = 3; f < 20; f++)
348			close(f);
349		execute(buf);
350		printf("can't execl!\r\n");
351		exit(0);
352	}
353}
354
355/*
356 * Interrupt service routine for FTP
357 */
358void
359stopsnd()
360{
361
362	stop = 1;
363	signal(SIGINT, SIG_IGN);
364}
365
366/*
367 * FTP - local ==> remote
368 *  send local file to remote host
369 *  terminate transmission with pseudo EOF sequence
370 */
371sendfile(cc)
372	char cc;
373{
374	FILE *fd;
375	char *fnamex;
376	char *expand();
377
378	putchar(cc);
379	/*
380	 * get file name
381	 */
382	if (prompt("Local file name? ", fname))
383		return;
384
385	/*
386	 * look up file
387	 */
388	fnamex = expand(fname);
389	if ((fd = fopen(fnamex, "r")) == NULL) {
390		printf("%s: cannot open\r\n", fname);
391		return;
392	}
393	transmit(fd, value(EOFWRITE), NULL);
394	if (!boolean(value(ECHOCHECK))) {
395		flush_remote ();
396	}
397}
398
399/*
400 * Bulk transfer routine to remote host --
401 *   used by sendfile() and cu_put()
402 */
403transmit(fd, eofchars, command)
404	FILE *fd;
405	char *eofchars, *command;
406{
407	char *pc, lastc;
408	int c, ccount, lcount;
409	time_t start_t, stop_t;
410	sig_t f;
411
412	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
413	stop = 0;
414	f = signal(SIGINT, stopsnd);
415	usedefchars ();
416	read(repdes[0], (char *)&ccc, 1);
417	if (command != NULL) {
418		for (pc = command; *pc; pc++)
419			send(*pc);
420		if (boolean(value(ECHOCHECK)))
421			read(FD, (char *)&c, 1);	/* trailing \n */
422		else {
423			flush_remote ();
424			sleep(5); /* wait for remote stty to take effect */
425		}
426	}
427	lcount = 0;
428	lastc = '\0';
429	start_t = time(0);
430	while (1) {
431		ccount = 0;
432		do {
433			c = getc(fd);
434			if (stop)
435				goto out;
436			if (c == EOF)
437				goto out;
438			if (c == 0177 && !boolean(value(RAWFTP)))
439				continue;
440			lastc = c;
441			if (c < 040) {
442				if (c == '\n') {
443					if (!boolean(value(RAWFTP)))
444						c = '\r';
445				}
446				else if (c == '\t') {
447					if (!boolean(value(RAWFTP))) {
448						if (boolean(value(TABEXPAND))) {
449							send(' ');
450							while ((++ccount % 8) != 0)
451								send(' ');
452							continue;
453						}
454					}
455				} else
456					if (!boolean(value(RAWFTP)))
457						continue;
458			}
459			send(c);
460		} while (c != '\r' && !boolean(value(RAWFTP)));
461		if (boolean(value(VERBOSE)))
462			printf("\r%d", ++lcount);
463		if (boolean(value(ECHOCHECK))) {
464			timedout = 0;
465			alarm((int)value(ETIMEOUT));
466			do {	/* wait for prompt */
467				read(FD, (char *)&c, 1);
468				if (timedout || stop) {
469					if (timedout)
470						printf("\r\ntimed out at eol\r\n");
471					alarm(0);
472					goto out;
473				}
474			} while ((c&0177) != character(value(PROMPT)));
475			alarm(0);
476		}
477	}
478out:
479	if (lastc != '\n' && !boolean(value(RAWFTP)))
480		send('\r');
481	for (pc = eofchars; *pc; pc++)
482		send(*pc);
483	stop_t = time(0);
484	fclose(fd);
485	signal(SIGINT, f);
486	if (boolean(value(VERBOSE)))
487		if (boolean(value(RAWFTP)))
488			prtime(" chars transferred in ", stop_t-start_t);
489		else
490			prtime(" lines transferred in ", stop_t-start_t);
491	write(fildes[1], (char *)&ccc, 1);
492	usetchars ();
493}
494
495/*
496 * Cu-like put command
497 */
498cu_put(cc)
499	char cc;
500{
501	FILE *fd;
502	char line[BUFSIZ];
503	int argc;
504	char *expand();
505	char *copynamex;
506
507	if (prompt("[put] ", copyname))
508		return;
509	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
510		printf("usage: <put> from [to]\r\n");
511		return;
512	}
513	if (argc == 1)
514		argv[1] = argv[0];
515	copynamex = expand(argv[0]);
516	if ((fd = fopen(copynamex, "r")) == NULL) {
517		printf("%s: cannot open\r\n", copynamex);
518		return;
519	}
520	if (boolean(value(ECHOCHECK)))
521		sprintf(line, "cat>%s\r", argv[1]);
522	else
523		sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
524	transmit(fd, "\04", line);
525}
526
527/*
528 * FTP - send single character
529 *  wait for echo & handle timeout
530 */
531send(c)
532	char c;
533{
534	char cc;
535	int retry = 0;
536
537	cc = c;
538	pwrite(FD, &cc, 1);
539#ifdef notdef
540	if (number(value(CDELAY)) > 0 && c != '\r')
541		nap(number(value(CDELAY)));
542#endif
543	if (!boolean(value(ECHOCHECK))) {
544#ifdef notdef
545		if (number(value(LDELAY)) > 0 && c == '\r')
546			nap(number(value(LDELAY)));
547#endif
548		return;
549	}
550tryagain:
551	timedout = 0;
552	alarm((int)value(ETIMEOUT));
553	read(FD, &cc, 1);
554	alarm(0);
555	if (timedout) {
556		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
557		if (retry++ > 3)
558			return;
559		pwrite(FD, &null, 1); /* poke it */
560		goto tryagain;
561	}
562}
563
564void
565timeout()
566{
567	signal(SIGALRM, timeout);
568	timedout = 1;
569}
570
571/*
572 * Stolen from consh() -- puts a remote file on the output of a local command.
573 *	Identical to consh() except for where stdout goes.
574 */
575pipeout(c)
576{
577	char buf[256];
578	int cpid, status, p;
579	time_t start;
580
581	putchar(c);
582	if (prompt("Local command? ", buf))
583		return;
584	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
585	signal(SIGINT, SIG_IGN);
586	signal(SIGQUIT, SIG_IGN);
587	usedefchars ();
588	read(repdes[0], (char *)&ccc, 1);
589	/*
590	 * Set up file descriptors in the child and
591	 *  let it go...
592	 */
593	if ((cpid = fork()) < 0)
594		printf("can't fork!\r\n");
595	else if (cpid) {
596		start = time(0);
597		while ((p = wait(&status)) > 0 && p != cpid)
598			;
599	} else {
600		register int i;
601
602		dup2(FD, 1);
603		for (i = 3; i < 20; i++)
604			close(i);
605		signal(SIGINT, SIG_DFL);
606		signal(SIGQUIT, SIG_DFL);
607		execute(buf);
608		printf("can't find `%s'\r\n", buf);
609		exit(0);
610	}
611	if (boolean(value(VERBOSE)))
612		prtime("away for ", time(0)-start);
613	write(fildes[1], (char *)&ccc, 1);
614	usetchars ();
615	signal(SIGINT, SIG_DFL);
616	signal(SIGQUIT, SIG_DFL);
617}
618
619#if CONNECT
620
621int
622tiplink (char *cmd, unsigned int flags)
623{
624	int cpid, status, p;
625	time_t start;
626
627	if (flags & TL_SIGNAL_TIPOUT) {
628		kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
629		signal(SIGINT, SIG_IGN);
630		signal(SIGQUIT, SIG_IGN);
631		usedefchars ();
632		read(repdes[0], (char *)&ccc, 1);
633	}
634
635	/*
636	 * Set up file descriptors in the child and
637	 *  let it go...
638	 */
639	if ((cpid = fork()) < 0)
640		printf("can't fork!\r\n");
641	else if (cpid) {
642		start = time(0);
643		while ((p = wait(&status)) > 0 && p != cpid)
644			;
645	} else {
646		register int fd;
647
648		dup2(FD, 0);
649		dup2(3, 1);
650		for (fd = 3; fd < 20; fd++)
651			close (fd);
652		signal(SIGINT, SIG_DFL);
653		signal(SIGQUIT, SIG_DFL);
654		execute (cmd);
655		printf("can't find `%s'\r\n", cmd);
656		exit(0);
657	}
658
659	if (flags & TL_VERBOSE && boolean(value(VERBOSE)))
660		prtime("away for ", time(0)-start);
661
662	if (flags & TL_SIGNAL_TIPOUT) {
663		write(fildes[1], (char *)&ccc, 1);
664		usetchars ();
665		signal(SIGINT, SIG_DFL);
666		signal(SIGQUIT, SIG_DFL);
667	}
668
669	return 0;
670}
671
672/*
673 * Fork a program with:
674 *  0 <-> remote tty in
675 *  1 <-> remote tty out
676 *  2 <-> local tty out
677 */
678consh(c)
679{
680	char buf[256];
681	putchar(c);
682	if (prompt("Local command? ", buf))
683		return;
684	tiplink (buf, TL_SIGNAL_TIPOUT | TL_VERBOSE);
685}
686#endif
687
688/*
689 * Escape to local shell
690 */
691shell()
692{
693	int shpid, status;
694	extern char **environ;
695	char *cp;
696
697	printf("[sh]\r\n");
698	signal(SIGINT, SIG_IGN);
699	signal(SIGQUIT, SIG_IGN);
700	unraw();
701	if (shpid = fork()) {
702		while (shpid != wait(&status));
703		raw();
704		printf("\r\n!\r\n");
705		signal(SIGINT, SIG_DFL);
706		signal(SIGQUIT, SIG_DFL);
707		return;
708	} else {
709		signal(SIGQUIT, SIG_DFL);
710		signal(SIGINT, SIG_DFL);
711		if ((cp = rindex(value(SHELL), '/')) == NULL)
712			cp = value(SHELL);
713		else
714			cp++;
715		shell_uid();
716		execl(value(SHELL), cp, 0);
717		printf("\r\ncan't execl!\r\n");
718		exit(1);
719	}
720}
721
722/*
723 * TIPIN portion of scripting
724 *   initiate the conversation with TIPOUT
725 */
726setscript()
727{
728	char c;
729	/*
730	 * enable TIPOUT side for dialogue
731	 */
732	kill(pid, SIGEMT);
733	if (boolean(value(SCRIPT)))
734		write(fildes[1], value(RECORD), size(value(RECORD)));
735	write(fildes[1], "\n", 1);
736	/*
737	 * wait for TIPOUT to finish
738	 */
739	read(repdes[0], &c, 1);
740	if (c == 'n')
741		printf("can't create %s\r\n", value(RECORD));
742}
743
744/*
745 * Change current working directory of
746 *   local portion of tip
747 */
748chdirectory()
749{
750	char dirname[80];
751	register char *cp = dirname;
752
753	if (prompt("[cd] ", dirname)) {
754		if (stoprompt)
755			return;
756		cp = value(HOME);
757	}
758	if (chdir(cp) < 0)
759		printf("%s: bad directory\r\n", cp);
760	printf("!\r\n");
761}
762
763tipabort(msg)
764	char *msg;
765{
766
767	kill(pid, SIGTERM);
768	disconnect(msg);
769	if (msg != NOSTR)
770		printf("\r\n%s", msg);
771	printf("\r\n[EOT]\r\n");
772	daemon_uid();
773	(void)uu_unlock(uucplock);
774	unraw();
775	exit(0);
776}
777
778finish()
779{
780	char *abortmsg = NOSTR, *dismsg;
781
782	if (LO != NOSTR && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) {
783		abortmsg = "logout failed";
784	}
785
786	if ((dismsg = value(DISCONNECT)) != NOSTR) {
787		write(FD, dismsg, strlen(dismsg));
788		sleep (2);
789	}
790	tipabort(abortmsg);
791}
792
793void
794intcopy()
795{
796	raw();
797	quit = 1;
798	longjmp(intbuf, 1);
799}
800
801execute(s)
802	char *s;
803{
804	register char *cp;
805
806	if ((cp = rindex(value(SHELL), '/')) == NULL)
807		cp = value(SHELL);
808	else
809		cp++;
810	shell_uid();
811	execl(value(SHELL), cp, "-c", s, 0);
812}
813
814args(buf, a)
815	char *buf, *a[];
816{
817	register char *p = buf, *start;
818	register char **parg = a;
819	register int n = 0;
820
821	do {
822		while (*p && (*p == ' ' || *p == '\t'))
823			p++;
824		start = p;
825		if (*p)
826			*parg = p;
827		while (*p && (*p != ' ' && *p != '\t'))
828			p++;
829		if (p != start)
830			parg++, n++;
831		if (*p)
832			*p++ = '\0';
833	} while (*p);
834
835	return(n);
836}
837
838prtime(s, a)
839	char *s;
840	time_t a;
841{
842	register i;
843	int nums[3];
844
845	for (i = 0; i < 3; i++) {
846		nums[i] = (int)(a % quant[i]);
847		a /= quant[i];
848	}
849	printf("%s", s);
850	while (--i >= 0)
851		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
852			printf("%d %s%c ", nums[i], sep[i],
853				nums[i] == 1 ? '\0' : 's');
854	printf("\r\n!\r\n");
855}
856
857variable()
858{
859	char	buf[256];
860
861	if (prompt("[set] ", buf))
862		return;
863	vlex(buf);
864	if (vtable[BEAUTIFY].v_access&CHANGED) {
865		vtable[BEAUTIFY].v_access &= ~CHANGED;
866		kill(pid, SIGSYS);
867	}
868	if (vtable[SCRIPT].v_access&CHANGED) {
869		vtable[SCRIPT].v_access &= ~CHANGED;
870		setscript();
871		/*
872		 * So that "set record=blah script" doesn't
873		 *  cause two transactions to occur.
874		 */
875		if (vtable[RECORD].v_access&CHANGED)
876			vtable[RECORD].v_access &= ~CHANGED;
877	}
878	if (vtable[RECORD].v_access&CHANGED) {
879		vtable[RECORD].v_access &= ~CHANGED;
880		if (boolean(value(SCRIPT)))
881			setscript();
882	}
883	if (vtable[TAND].v_access&CHANGED) {
884		vtable[TAND].v_access &= ~CHANGED;
885		if (boolean(value(TAND)))
886			tandem("on");
887		else
888			tandem("off");
889	}
890 	if (vtable[LECHO].v_access&CHANGED) {
891 		vtable[LECHO].v_access &= ~CHANGED;
892 		HD = boolean(value(LECHO));
893 	}
894	if (vtable[PARITY].v_access&CHANGED) {
895		vtable[PARITY].v_access &= ~CHANGED;
896		setparity();
897	}
898}
899
900/*
901 * Turn tandem mode on or off for remote tty.
902 */
903tandem(option)
904	char *option;
905{
906#if HAVE_TERMIOS
907	struct termios ttermios;
908	tcgetattr (FD, &ttermios);
909	if (strcmp(option,"on") == 0) {
910		ttermios.c_iflag |= IXOFF;
911		ctermios.c_iflag |= IXOFF;
912	}
913	else {
914		ttermios.c_iflag &= ~IXOFF;
915		ctermios.c_iflag &= ~IXOFF;
916	}
917	tcsetattr (FD, TCSANOW, &ttermios);
918	tcsetattr (0, TCSANOW, &ctermios);
919#else /* HAVE_TERMIOS */
920	struct sgttyb rmtty;
921
922	ioctl(FD, TIOCGETP, &rmtty);
923	if (strcmp(option,"on") == 0) {
924		rmtty.sg_flags |= TANDEM;
925		arg.sg_flags |= TANDEM;
926	} else {
927		rmtty.sg_flags &= ~TANDEM;
928		arg.sg_flags &= ~TANDEM;
929	}
930	ioctl(FD, TIOCSETP, &rmtty);
931	ioctl(0,  TIOCSETP, &arg);
932#endif /* HAVE_TERMIOS */
933}
934
935/*
936 * Send a break.
937 */
938genbrk()
939{
940
941	ioctl(FD, TIOCSBRK, NULL);
942	sleep(1);
943	ioctl(FD, TIOCCBRK, NULL);
944}
945
946/*
947 * Suspend tip
948 */
949suspend(c)
950	char c;
951{
952
953	unraw();
954	kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
955	raw();
956}
957
958/*
959 *	expand a file name if it includes shell meta characters
960 */
961
962char *
963expand(name)
964	char name[];
965{
966	static char xname[BUFSIZ];
967	char cmdbuf[BUFSIZ];
968	register int pid, l, rc;
969	register char *cp, *Shell;
970	int s, pivec[2], (*sigint)();
971
972	if (!anyof(name, "~{[*?$`'\"\\"))
973		return(name);
974	/* sigint = signal(SIGINT, SIG_IGN); */
975	if (pipe(pivec) < 0) {
976		perror("pipe");
977		/* signal(SIGINT, sigint) */
978		return(name);
979	}
980	sprintf(cmdbuf, "echo %s", name);
981	if ((pid = vfork()) == 0) {
982		Shell = value(SHELL);
983		if (Shell == NOSTR)
984			Shell = _PATH_BSHELL;
985		close(pivec[0]);
986		close(1);
987		dup(pivec[1]);
988		close(pivec[1]);
989		close(2);
990		shell_uid();
991		execl(Shell, Shell, "-c", cmdbuf, 0);
992		_exit(1);
993	}
994	if (pid == -1) {
995		perror("fork");
996		close(pivec[0]);
997		close(pivec[1]);
998		return(NOSTR);
999	}
1000	close(pivec[1]);
1001	l = read(pivec[0], xname, BUFSIZ);
1002	close(pivec[0]);
1003	while (wait(&s) != pid);
1004		;
1005	s &= 0377;
1006	if (s != 0 && s != SIGPIPE) {
1007		fprintf(stderr, "\"Echo\" failed\n");
1008		return(NOSTR);
1009	}
1010	if (l < 0) {
1011		perror("read");
1012		return(NOSTR);
1013	}
1014	if (l == 0) {
1015		fprintf(stderr, "\"%s\": No match\n", name);
1016		return(NOSTR);
1017	}
1018	if (l == BUFSIZ) {
1019		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
1020		return(NOSTR);
1021	}
1022	xname[l] = 0;
1023	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
1024		;
1025	*++cp = '\0';
1026	return(xname);
1027}
1028
1029/*
1030 * Are any of the characters in the two strings the same?
1031 */
1032
1033anyof(s1, s2)
1034	register char *s1, *s2;
1035{
1036	register int c;
1037
1038	while (c = *s1++)
1039		if (any(c, s2))
1040			return(1);
1041	return(0);
1042}
1043