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