xref: /onnv-gate/usr/src/cmd/tip/cmds.c (revision 549)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
5*549Smuffin 
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
80Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
90Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
100Sstevel@tonic-gate  */
110Sstevel@tonic-gate 
12*549Smuffin #pragma ident	"%Z%%M%	%I%	%E% SMI"
130Sstevel@tonic-gate 
140Sstevel@tonic-gate #include "tip.h"
150Sstevel@tonic-gate #ifdef USG
160Sstevel@tonic-gate #include <unistd.h>
170Sstevel@tonic-gate #else
180Sstevel@tonic-gate #include <vfork.h>
190Sstevel@tonic-gate #endif
200Sstevel@tonic-gate 
210Sstevel@tonic-gate /*
220Sstevel@tonic-gate  * tip
230Sstevel@tonic-gate  *
240Sstevel@tonic-gate  * miscellaneous commands
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate int	quant[] = { 60, 60, 24 };
280Sstevel@tonic-gate 
290Sstevel@tonic-gate char	null = '\0';
300Sstevel@tonic-gate char	*sep[] = { "second", "minute", "hour" };
310Sstevel@tonic-gate static	char *argv[10];		/* argument vector for take and put */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate sigjmp_buf intbuf;		/* for interrupts and timeouts */
340Sstevel@tonic-gate 
35*549Smuffin void	timeout(void);		/* timeout function called on alarm */
36*549Smuffin void	intcopy(void);		/* interrupt routine for file transfers */
37*549Smuffin void	transfer(char *, int, char *);
38*549Smuffin void	transmit(FILE *, char *, char *);
39*549Smuffin void	send(char);
40*549Smuffin void	execute(char *);
41*549Smuffin void	prtime(char *, time_t);
42*549Smuffin void	hardwareflow(char *);
43*549Smuffin void	intr(char *);
44*549Smuffin int	args(char *, char *[], size_t);
45*549Smuffin int	anyof(char *, char *);
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate  * FTP - remote ==> local
490Sstevel@tonic-gate  *  get a file from the remote host
500Sstevel@tonic-gate  */
51*549Smuffin void
52*549Smuffin getfl(int c)
530Sstevel@tonic-gate {
54*549Smuffin 	char buf[256], *cp;
550Sstevel@tonic-gate 
56*549Smuffin 	(void) putchar(c);
570Sstevel@tonic-gate 	/*
580Sstevel@tonic-gate 	 * get the UNIX receiving file's name
590Sstevel@tonic-gate 	 */
600Sstevel@tonic-gate 	if (prompt("Local file name? ", copyname, sizeof (copyname)))
610Sstevel@tonic-gate 		return;
620Sstevel@tonic-gate 	cp = expand(copyname);
630Sstevel@tonic-gate 	if (cp == NOSTR)
640Sstevel@tonic-gate 		return;
650Sstevel@tonic-gate 	if ((sfd = creat(cp, 0666)) < 0) {
66*549Smuffin 		(void) printf("\r\n%s: cannot creat\r\n", copyname);
670Sstevel@tonic-gate 		return;
680Sstevel@tonic-gate 	}
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	/*
710Sstevel@tonic-gate 	 * collect parameters
720Sstevel@tonic-gate 	 */
730Sstevel@tonic-gate 	if (prompt("List command for remote system? ", buf, sizeof (buf))) {
74*549Smuffin 		(void) unlink(copyname);
750Sstevel@tonic-gate 		return;
760Sstevel@tonic-gate 	}
770Sstevel@tonic-gate 	transfer(buf, sfd, value(EOFREAD));
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * Cu-like take command
820Sstevel@tonic-gate  */
83*549Smuffin /* ARGSUSED */
84*549Smuffin void
85*549Smuffin cu_take(int cc)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate 	int fd, argc;
88*549Smuffin 	char line[BUFSIZ], *cp;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	if (prompt("[take] ", copyname, sizeof (copyname)))
910Sstevel@tonic-gate 		return;
920Sstevel@tonic-gate 	argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
930Sstevel@tonic-gate 	if (argc < 1 || argc > 2) {
94*549Smuffin 		(void) printf("usage: <take> from [to]\r\n");
950Sstevel@tonic-gate 		return;
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 	if (argc == 1)
980Sstevel@tonic-gate 		argv[1] = argv[0];
990Sstevel@tonic-gate 	cp = expand(argv[1]);
1000Sstevel@tonic-gate 	if (cp == NOSTR)
1010Sstevel@tonic-gate 		return;
1020Sstevel@tonic-gate 	if ((fd = creat(cp, 0666)) < 0) {
103*549Smuffin 		(void) printf("\r\n%s: cannot create\r\n", argv[1]);
1040Sstevel@tonic-gate 		return;
1050Sstevel@tonic-gate 	}
106*549Smuffin 	(void) snprintf(line, sizeof (line), "cat %s; echo \01", argv[0]);
1070Sstevel@tonic-gate 	transfer(line, fd, "\01");
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate  * Bulk transfer routine --
1120Sstevel@tonic-gate  *  used by getfl(), cu_take(), and pipefile()
1130Sstevel@tonic-gate  */
114*549Smuffin void
115*549Smuffin transfer(char *buf, int fd, char *eofchars)
1160Sstevel@tonic-gate {
117*549Smuffin 	int ct;
1180Sstevel@tonic-gate 	char c, buffer[BUFSIZ];
1190Sstevel@tonic-gate 	char *p = buffer;	/* can't be register because of longjmp */
120*549Smuffin 	int cnt, eof, bol;
1210Sstevel@tonic-gate 	time_t start;
122*549Smuffin 	sig_handler_t	f;
1230Sstevel@tonic-gate 
124*549Smuffin 	parwrite(FD, (unsigned char *)buf, strlen(buf));
125*549Smuffin 	(void) kill(pid, SIGIOT);
126*549Smuffin 	/* Wait until read process stops */
127*549Smuffin 	(void) read(repdes[0], (char *)&ccc, 1);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	/*
1300Sstevel@tonic-gate 	 * finish command
1310Sstevel@tonic-gate 	 */
132*549Smuffin 	parwrite(FD, (unsigned char *)"\r", 1);
1330Sstevel@tonic-gate 	do
134*549Smuffin 		(void) read(FD, &c, 1);
135*549Smuffin 	while ((c&0177) != '\n')
136*549Smuffin 		;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (sigsetjmp(intbuf, 1))
1390Sstevel@tonic-gate 		goto out;
140*549Smuffin 	f = signal(SIGINT, (sig_handler_t)intcopy);
1410Sstevel@tonic-gate 	intr("on");
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	start = time(0);
1440Sstevel@tonic-gate 	bol = 1;
1450Sstevel@tonic-gate 	ct = 0;
1460Sstevel@tonic-gate 	for (;;) {
1470Sstevel@tonic-gate 		eof = read(FD, &c, 1) <= 0;
1480Sstevel@tonic-gate 		if (noparity)
1490Sstevel@tonic-gate 			c &= 0377;
1500Sstevel@tonic-gate 		else
1510Sstevel@tonic-gate 			c &= 0177;
1520Sstevel@tonic-gate 		if (eof || (bol && any(c, eofchars)))
1530Sstevel@tonic-gate 			break;
1540Sstevel@tonic-gate 		if (c == 0)
1550Sstevel@tonic-gate 			continue;	/* ignore nulls */
1560Sstevel@tonic-gate 		if (c == '\r')
1570Sstevel@tonic-gate 			continue;
1580Sstevel@tonic-gate 		*p++ = c;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 		if (c == '\n') {
1610Sstevel@tonic-gate 			bol = 1;
1620Sstevel@tonic-gate 			if (boolean(value(VERBOSE)))
163*549Smuffin 				(void) printf("\r%d", ++ct);
1640Sstevel@tonic-gate 		} else
1650Sstevel@tonic-gate 			bol = 0;
1660Sstevel@tonic-gate 		if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
1670Sstevel@tonic-gate 			if (write(fd, buffer, cnt) != cnt) {
168*549Smuffin 				(void) printf("\r\nwrite error\r\n");
1690Sstevel@tonic-gate 				goto out;
1700Sstevel@tonic-gate 			}
1710Sstevel@tonic-gate 			p = buffer;
1720Sstevel@tonic-gate 		}
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate out:
175*549Smuffin 	if ((cnt = (p-buffer)) != 0)
1760Sstevel@tonic-gate 		if (write(fd, buffer, cnt) != cnt)
177*549Smuffin 			(void) printf("\r\nwrite error\r\n");
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
1800Sstevel@tonic-gate 		prtime(" lines transferred in ", time(0)-start);
1810Sstevel@tonic-gate 	intr("off");
182*549Smuffin 	(void) write(fildes[1], (char *)&ccc, 1);
183*549Smuffin 	(void) signal(SIGINT, f);
184*549Smuffin 	(void) close(fd);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * FTP - remote ==> local process
1890Sstevel@tonic-gate  *   send remote input to local process via pipe
1900Sstevel@tonic-gate  */
191*549Smuffin /* ARGSUSED */
192*549Smuffin void
193*549Smuffin pipefile(int cc)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	int cpid, pdes[2];
1960Sstevel@tonic-gate 	char buf[256];
1970Sstevel@tonic-gate 	int status, p;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (prompt("Local command? ", buf, sizeof (buf)))
2000Sstevel@tonic-gate 		return;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if (pipe(pdes)) {
203*549Smuffin 		(void) printf("can't establish pipe\r\n");
2040Sstevel@tonic-gate 		return;
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	if ((cpid = fork()) < 0) {
208*549Smuffin 		(void) printf("can't fork!\r\n");
2090Sstevel@tonic-gate 		return;
2100Sstevel@tonic-gate 	} else if (cpid) {
2110Sstevel@tonic-gate 		if (prompt("List command for remote system? ", buf,
212*549Smuffin 		    sizeof (buf))) {
213*549Smuffin 			(void) close(pdes[0]), (void) close(pdes[1]);
214*549Smuffin 			(void) kill(cpid, SIGKILL);
2150Sstevel@tonic-gate 		} else {
216*549Smuffin 			(void) close(pdes[0]);
217*549Smuffin 			(void) signal(SIGPIPE, (sig_handler_t)intcopy);
2180Sstevel@tonic-gate 			transfer(buf, pdes[1], value(EOFREAD));
219*549Smuffin 			(void) signal(SIGPIPE, SIG_DFL);
2200Sstevel@tonic-gate 			while ((p = wait(&status)) > 0 && p != cpid)
2210Sstevel@tonic-gate 				;
2220Sstevel@tonic-gate 		}
2230Sstevel@tonic-gate 	} else {
224*549Smuffin 		int f;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		userperm();
227*549Smuffin 		(void) dup2(pdes[0], 0);
228*549Smuffin 		(void) close(pdes[0]);
2290Sstevel@tonic-gate 		for (f = 3; f < 20; f++)
230*549Smuffin 			(void) close(f);
2310Sstevel@tonic-gate 		execute(buf);
232*549Smuffin 		(void) printf("can't execl!\r\n");
2330Sstevel@tonic-gate 		exit(0);
2340Sstevel@tonic-gate 	}
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  * FTP - local ==> remote
2390Sstevel@tonic-gate  *  send local file to remote host
2400Sstevel@tonic-gate  *  terminate transmission with pseudo EOF sequence
2410Sstevel@tonic-gate  */
242*549Smuffin void
243*549Smuffin tip_sendfile(int cc)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate 	FILE *fd;
2460Sstevel@tonic-gate 	char *fnamex;
2470Sstevel@tonic-gate 
248*549Smuffin 	(void) putchar(cc);
2490Sstevel@tonic-gate 	/*
2500Sstevel@tonic-gate 	 * get file name
2510Sstevel@tonic-gate 	 */
2520Sstevel@tonic-gate 	if (prompt("Local file name? ", fname, sizeof (fname)))
2530Sstevel@tonic-gate 		return;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	/*
2560Sstevel@tonic-gate 	 * look up file
2570Sstevel@tonic-gate 	 */
2580Sstevel@tonic-gate 	fnamex = expand(fname);
2590Sstevel@tonic-gate 	if (fnamex == NOSTR)
2600Sstevel@tonic-gate 		return;
2610Sstevel@tonic-gate 	if ((fd = fopen(fnamex, "r")) == NULL) {
262*549Smuffin 		(void) printf("%s: cannot open\r\n", fname);
2630Sstevel@tonic-gate 		return;
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 	transmit(fd, value(EOFWRITE), NULL);
2660Sstevel@tonic-gate 	if (!boolean(value(ECHOCHECK))) {
2670Sstevel@tonic-gate 		struct termios buf;
2680Sstevel@tonic-gate 
269*549Smuffin 		(void) ioctl(FD, TCGETS, (char *)&buf);	/* this does a */
270*549Smuffin 		(void) ioctl(FD, TCSETSF, (char *)&buf);	/* wflushtty */
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate  * Bulk transfer routine to remote host --
276*549Smuffin  *   used by tip_sendfile() and cu_put()
2770Sstevel@tonic-gate  */
278*549Smuffin void
279*549Smuffin transmit(FILE *fd, char *eofchars, char *command)
2800Sstevel@tonic-gate {
281*549Smuffin 	sig_handler_t	ointr;
2820Sstevel@tonic-gate 	char *pc, lastc, rc;
2830Sstevel@tonic-gate 	int c, ccount, lcount;
2840Sstevel@tonic-gate 	time_t start_t, stop_t;
2850Sstevel@tonic-gate 
286*549Smuffin 	(void) kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
2870Sstevel@tonic-gate 	timedout = 0;
2880Sstevel@tonic-gate 	if (sigsetjmp(intbuf, 1)) {
2890Sstevel@tonic-gate 		if (timedout)
290*549Smuffin 			(void) printf("\r\ntimed out at eol\r\n");
291*549Smuffin 		(void) alarm(0);
2920Sstevel@tonic-gate 		goto out;
2930Sstevel@tonic-gate 	}
294*549Smuffin 	ointr = signal(SIGINT, (sig_handler_t)intcopy);
2950Sstevel@tonic-gate 	intr("on");
296*549Smuffin 	(void) read(repdes[0], (char *)&ccc, 1);
2970Sstevel@tonic-gate 	if (command != NULL) {
2980Sstevel@tonic-gate 		for (pc = command; *pc; pc++)
2990Sstevel@tonic-gate 			send(*pc);
3000Sstevel@tonic-gate 		if (boolean(value(ECHOCHECK)))
301*549Smuffin 			(void) read(FD, (char *)&c, 1);	/* trailing \n */
3020Sstevel@tonic-gate 		else {
3030Sstevel@tonic-gate 			struct termios buf;
304*549Smuffin 			/* wait for remote stty to take effect */
305*549Smuffin 			(void) sleep(5);
306*549Smuffin 			/* this does a */
307*549Smuffin 			(void) ioctl(FD, TCGETS, (char *)&buf);
308*549Smuffin 			/* wflushtty */
309*549Smuffin 			(void) ioctl(FD, TCSETSF, (char *)&buf);
3100Sstevel@tonic-gate 		}
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 	lcount = 0;
3130Sstevel@tonic-gate 	lastc = '\0';
3140Sstevel@tonic-gate 	start_t = time(0);
3150Sstevel@tonic-gate 	if (boolean(value(RAWFTP))) {
3160Sstevel@tonic-gate 		while ((c = getc(fd)) != EOF) {
3170Sstevel@tonic-gate 			lcount++;
3180Sstevel@tonic-gate 			send(c);
3190Sstevel@tonic-gate 			if (boolean(value(VERBOSE)) && lcount%100 == 0)
320*549Smuffin 				(void) printf("\r%d", lcount);
3210Sstevel@tonic-gate 		}
3220Sstevel@tonic-gate 		if (boolean(value(VERBOSE)))
323*549Smuffin 			(void) printf("\r%d", lcount);
3240Sstevel@tonic-gate 		goto out;
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 	for (;;) {
3270Sstevel@tonic-gate 		ccount = 0;
3280Sstevel@tonic-gate 		do {
3290Sstevel@tonic-gate 			c = getc(fd);
3300Sstevel@tonic-gate 			if (c == EOF)
3310Sstevel@tonic-gate 				goto out;
3320Sstevel@tonic-gate 			if (c == 0177)
3330Sstevel@tonic-gate 				continue;
3340Sstevel@tonic-gate 			lastc = c;
3350Sstevel@tonic-gate 			if (c < 040) {
3360Sstevel@tonic-gate 				if (c == '\n') {
3370Sstevel@tonic-gate 					c = '\r';
3380Sstevel@tonic-gate 				} else if (c == '\t') {
3390Sstevel@tonic-gate 					if (boolean(value(TABEXPAND))) {
3400Sstevel@tonic-gate 						send(' ');
3410Sstevel@tonic-gate 						while ((++ccount % 8) != 0)
3420Sstevel@tonic-gate 							send(' ');
3430Sstevel@tonic-gate 						continue;
3440Sstevel@tonic-gate 					}
3450Sstevel@tonic-gate 				} else
3460Sstevel@tonic-gate 					continue;
3470Sstevel@tonic-gate 			}
3480Sstevel@tonic-gate 			send(c);
3490Sstevel@tonic-gate 		} while (c != '\r');
3500Sstevel@tonic-gate 		if (boolean(value(VERBOSE)))
351*549Smuffin 			(void) printf("\r%d", ++lcount);
3520Sstevel@tonic-gate 		if (boolean(value(ECHOCHECK))) {
353*549Smuffin 			(void) alarm(number(value(ETIMEOUT)));
3540Sstevel@tonic-gate 			do {	/* wait for prompt */
355*549Smuffin 				(void) read(FD, &rc, 1);
3560Sstevel@tonic-gate 			} while ((rc&0177) != character(value(PROMPT)));
357*549Smuffin 			(void) alarm(0);
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate out:
3610Sstevel@tonic-gate 	if (lastc != '\n' && !boolean(value(RAWFTP)))
3620Sstevel@tonic-gate 		send('\r');
3630Sstevel@tonic-gate 	if (eofchars)
3640Sstevel@tonic-gate 		for (pc = eofchars; *pc; pc++)
3650Sstevel@tonic-gate 			send(*pc);
3660Sstevel@tonic-gate 	stop_t = time(0);
367*549Smuffin 	(void) fclose(fd);
3680Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
3690Sstevel@tonic-gate 		if (boolean(value(RAWFTP)))
3700Sstevel@tonic-gate 			prtime(" chars transferred in ", stop_t-start_t);
3710Sstevel@tonic-gate 		else
3720Sstevel@tonic-gate 			prtime(" lines transferred in ", stop_t-start_t);
373*549Smuffin 	(void) write(fildes[1], (char *)&ccc, 1);
3740Sstevel@tonic-gate 	intr("off");
375*549Smuffin 	(void) signal(SIGINT, ointr);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate  * Cu-like put command
3800Sstevel@tonic-gate  */
381*549Smuffin /* ARGSUSED */
382*549Smuffin void
383*549Smuffin cu_put(int cc)
3840Sstevel@tonic-gate {
3850Sstevel@tonic-gate 	FILE *fd;
3860Sstevel@tonic-gate 	char line[BUFSIZ];
3870Sstevel@tonic-gate 	int argc;
3880Sstevel@tonic-gate 	char *copynamex;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	if (prompt("[put] ", copyname, sizeof (copyname)))
3910Sstevel@tonic-gate 		return;
3920Sstevel@tonic-gate 	argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
3930Sstevel@tonic-gate 	if (argc < 1 || argc > 2) {
394*549Smuffin 		(void) printf("usage: <put> from [to]\r\n");
3950Sstevel@tonic-gate 		return;
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 	if (argc == 1)
3980Sstevel@tonic-gate 		argv[1] = argv[0];
3990Sstevel@tonic-gate 	copynamex = expand(argv[0]);
4000Sstevel@tonic-gate 	if (copynamex == NOSTR)
4010Sstevel@tonic-gate 		return;
4020Sstevel@tonic-gate 	if ((fd = fopen(copynamex, "r")) == NULL) {
403*549Smuffin 		(void) printf("%s: cannot open\r\n", copynamex);
4040Sstevel@tonic-gate 		return;
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 	if (boolean(value(ECHOCHECK)))
407*549Smuffin 		(void) snprintf(line, sizeof (line), "cat>%s\r", argv[1]);
4080Sstevel@tonic-gate 	else
409*549Smuffin 		(void) snprintf(line, sizeof (line),
410*549Smuffin 		    "stty -echo; cat>%s; stty echo\r", argv[1]);
4110Sstevel@tonic-gate 	transmit(fd, "\04", line);
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate /*
4150Sstevel@tonic-gate  * FTP - send single character
4160Sstevel@tonic-gate  *  wait for echo & handle timeout
4170Sstevel@tonic-gate  */
418*549Smuffin void
419*549Smuffin send(char c)
4200Sstevel@tonic-gate {
4210Sstevel@tonic-gate 	char cc;
4220Sstevel@tonic-gate 	int retry = 0;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	cc = c;
425*549Smuffin 	parwrite(FD, (unsigned char *)&cc, 1);
4260Sstevel@tonic-gate #ifdef notdef
4270Sstevel@tonic-gate 	if (number(value(CDELAY)) > 0 && c != '\r')
4280Sstevel@tonic-gate 		nap(number(value(CDELAY)));
4290Sstevel@tonic-gate #endif
4300Sstevel@tonic-gate 	if (!boolean(value(ECHOCHECK))) {
4310Sstevel@tonic-gate #ifdef notdef
4320Sstevel@tonic-gate 		if (number(value(LDELAY)) > 0 && c == '\r')
4330Sstevel@tonic-gate 			nap(number(value(LDELAY)));
4340Sstevel@tonic-gate #endif
4350Sstevel@tonic-gate 		return;
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate tryagain:
4380Sstevel@tonic-gate 	timedout = 0;
4390Sstevel@tonic-gate 	if (sigsetjmp(intbuf, 1) && timedout) {
440*549Smuffin 		(void) printf("\r\ntimeout error (%s)\r\n", ctrl(c));
4410Sstevel@tonic-gate 		if (retry++ > 3)
4420Sstevel@tonic-gate 			return;
443*549Smuffin 		parwrite(FD, (unsigned char *)&null, 1); /* poke it */
4440Sstevel@tonic-gate 		goto tryagain;
4450Sstevel@tonic-gate 	}
446*549Smuffin 	(void) alarm(number(value(ETIMEOUT)));
447*549Smuffin 	(void) read(FD, &cc, 1);
448*549Smuffin 	(void) alarm(0);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate void
452*549Smuffin timeout(void)
4530Sstevel@tonic-gate {
454*549Smuffin 	(void) signal(SIGALRM, (sig_handler_t)timeout);
4550Sstevel@tonic-gate 	timedout = 1;
4560Sstevel@tonic-gate 	siglongjmp(intbuf, 1);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate /*
4600Sstevel@tonic-gate  * Stolen from consh() -- puts a remote file on the output of a local command.
4610Sstevel@tonic-gate  *	Identical to consh() except for where stdout goes.
4620Sstevel@tonic-gate  */
463*549Smuffin void
464*549Smuffin pipeout(int c)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate 	char buf[256];
4670Sstevel@tonic-gate 	int cpid, status, p;
4680Sstevel@tonic-gate 	time_t start;
4690Sstevel@tonic-gate 
470*549Smuffin 	(void) putchar(c);
4710Sstevel@tonic-gate 	if (prompt("Local command? ", buf, sizeof (buf)))
4720Sstevel@tonic-gate 		return;
473*549Smuffin 	(void) kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
474*549Smuffin 	(void) signal(SIGINT, SIG_IGN);
475*549Smuffin 	(void) signal(SIGQUIT, SIG_IGN);
4760Sstevel@tonic-gate 	intr("on");
477*549Smuffin 	(void) read(repdes[0], (char *)&ccc, 1);
4780Sstevel@tonic-gate 	/*
4790Sstevel@tonic-gate 	 * Set up file descriptors in the child and
4800Sstevel@tonic-gate 	 *  let it go...
4810Sstevel@tonic-gate 	 */
4820Sstevel@tonic-gate 	if ((cpid = fork()) < 0)
483*549Smuffin 		(void) printf("can't fork!\r\n");
4840Sstevel@tonic-gate 	else if (cpid) {
4850Sstevel@tonic-gate 		start = time(0);
4860Sstevel@tonic-gate 		while ((p = wait(&status)) > 0 && p != cpid)
4870Sstevel@tonic-gate 			;
4880Sstevel@tonic-gate 	} else {
489*549Smuffin 		int i;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 		userperm();
492*549Smuffin 		(void) dup2(FD, 1);
4930Sstevel@tonic-gate 		for (i = 3; i < 20; i++)
494*549Smuffin 			(void) close(i);
495*549Smuffin 		(void) signal(SIGINT, SIG_DFL);
496*549Smuffin 		(void) signal(SIGQUIT, SIG_DFL);
4970Sstevel@tonic-gate 		execute(buf);
498*549Smuffin 		(void) printf("can't find `%s'\r\n", buf);
4990Sstevel@tonic-gate 		exit(0);
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
5020Sstevel@tonic-gate 		prtime("away for ", time(0)-start);
503*549Smuffin 	(void) write(fildes[1], (char *)&ccc, 1);
5040Sstevel@tonic-gate 	intr("off");
505*549Smuffin 	(void) signal(SIGINT, SIG_DFL);
506*549Smuffin 	(void) signal(SIGQUIT, SIG_DFL);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate /*
5100Sstevel@tonic-gate  * Fork a program with:
5110Sstevel@tonic-gate  *  0 <-> remote tty in
5120Sstevel@tonic-gate  *  1 <-> remote tty out
5130Sstevel@tonic-gate  *  2 <-> local tty stderr out
5140Sstevel@tonic-gate  */
515*549Smuffin void
516*549Smuffin consh(int c)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	char buf[256];
5190Sstevel@tonic-gate 	int cpid, status, p;
520*549Smuffin 	sig_handler_t	ointr, oquit;
5210Sstevel@tonic-gate 	time_t start;
5220Sstevel@tonic-gate 
523*549Smuffin 	(void) putchar(c);
5240Sstevel@tonic-gate 	if (prompt("Local command? ", buf, sizeof (buf)))
5250Sstevel@tonic-gate 		return;
526*549Smuffin 	(void) kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
527*549Smuffin 	(void) read(repdes[0], (char *)&ccc, 1);
5280Sstevel@tonic-gate 	ointr = signal(SIGINT, SIG_IGN);
5290Sstevel@tonic-gate 	oquit = signal(SIGQUIT, SIG_IGN);
5300Sstevel@tonic-gate 	unraw();
5310Sstevel@tonic-gate 	/*
5320Sstevel@tonic-gate 	 * Set up file descriptors in the child and
5330Sstevel@tonic-gate 	 *  let it go...
5340Sstevel@tonic-gate 	 */
5350Sstevel@tonic-gate 	if ((cpid = fork()) < 0)
536*549Smuffin 		(void) printf("can't fork!\r\n");
5370Sstevel@tonic-gate 	else if (cpid) {
5380Sstevel@tonic-gate 		start = time(0);
5390Sstevel@tonic-gate 		while ((p = wait(&status)) > 0 && p != cpid)
5400Sstevel@tonic-gate 			;
5410Sstevel@tonic-gate 		raw();
542*549Smuffin 		(void) signal(SIGINT, ointr);
543*549Smuffin 		(void) signal(SIGQUIT, oquit);
5440Sstevel@tonic-gate 	} else {
545*549Smuffin 		int i;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		userperm();
548*549Smuffin 		(void) dup2(FD, 0);
549*549Smuffin 		(void) dup2(0, 1);
5500Sstevel@tonic-gate 		for (i = 3; i < 20; i++)
551*549Smuffin 			(void) close(i);
552*549Smuffin 		(void) signal(SIGINT, SIG_DFL);
553*549Smuffin 		(void) signal(SIGQUIT, SIG_DFL);
5540Sstevel@tonic-gate 		execute(buf);
555*549Smuffin 		(void) printf("can't find `%s'\r\n", buf);
5560Sstevel@tonic-gate 		exit(0);
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
5590Sstevel@tonic-gate 		prtime("\r\naway for ", time(0)-start);
560*549Smuffin 	(void) write(fildes[1], (char *)&ccc, 1);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate /*
5640Sstevel@tonic-gate  * Escape to local shell
5650Sstevel@tonic-gate  */
566*549Smuffin /* ARGSUSED */
567*549Smuffin void
568*549Smuffin shell(int cc)
5690Sstevel@tonic-gate {
5700Sstevel@tonic-gate 	int shpid, status;
571*549Smuffin 	sig_handler_t	ointr, oquit;
5720Sstevel@tonic-gate 	char *cp;
5730Sstevel@tonic-gate 
574*549Smuffin 	(void) printf("[sh]\r\n");
5750Sstevel@tonic-gate 	ointr = signal(SIGINT, SIG_IGN);
5760Sstevel@tonic-gate 	oquit = signal(SIGQUIT, SIG_IGN);
5770Sstevel@tonic-gate 	unraw();
5780Sstevel@tonic-gate 	if (shpid = fork()) {
5790Sstevel@tonic-gate 		while (shpid != wait(&status))
5800Sstevel@tonic-gate 			;
5810Sstevel@tonic-gate 		raw();
582*549Smuffin 		(void) printf("\r\n!\r\n");
583*549Smuffin 		(void) signal(SIGINT, ointr);
584*549Smuffin 		(void) signal(SIGQUIT, oquit);
5850Sstevel@tonic-gate 	} else {
5860Sstevel@tonic-gate 		userperm();
587*549Smuffin 		(void) signal(SIGQUIT, SIG_DFL);
588*549Smuffin 		(void) signal(SIGINT, SIG_DFL);
5890Sstevel@tonic-gate 		if ((cp = strrchr(value(SHELL), '/')) == NULL)
5900Sstevel@tonic-gate 			cp = value(SHELL);
5910Sstevel@tonic-gate 		else
5920Sstevel@tonic-gate 			cp++;
593*549Smuffin 		(void) execl(value(SHELL), cp, 0);
594*549Smuffin 		(void) printf("\r\ncan't execl!\r\n");
5950Sstevel@tonic-gate 		exit(1);
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate  * TIPIN portion of scripting
6010Sstevel@tonic-gate  *   initiate the conversation with TIPOUT
6020Sstevel@tonic-gate  */
603*549Smuffin void
604*549Smuffin setscript(void)
6050Sstevel@tonic-gate {
6060Sstevel@tonic-gate 	char c;
6070Sstevel@tonic-gate 	/*
6080Sstevel@tonic-gate 	 * enable TIPOUT side for dialogue
6090Sstevel@tonic-gate 	 */
610*549Smuffin 	(void) kill(pid, SIGEMT);
6110Sstevel@tonic-gate 	if (boolean(value(SCRIPT)))
612*549Smuffin 		(void) write(fildes[1], value(RECORD), strlen(value(RECORD)));
613*549Smuffin 	(void) write(fildes[1], "\n", 1);
6140Sstevel@tonic-gate 	/*
6150Sstevel@tonic-gate 	 * wait for TIPOUT to finish
6160Sstevel@tonic-gate 	 */
617*549Smuffin 	(void) read(repdes[0], &c, 1);
6180Sstevel@tonic-gate 	if (c == 'n')
619*549Smuffin 		(void) fprintf(stderr, "tip: can't create record file %s\r\n",
6200Sstevel@tonic-gate 		    value(RECORD));
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate  * Change current working directory of
6250Sstevel@tonic-gate  *   local portion of tip
6260Sstevel@tonic-gate  */
627*549Smuffin /* ARGSUSED */
628*549Smuffin void
629*549Smuffin chdirectory(int cc)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate 	char dirname[80];
632*549Smuffin 	char *cp = dirname;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	if (prompt("[cd] ", dirname, sizeof (dirname))) {
6350Sstevel@tonic-gate 		if (stoprompt)
6360Sstevel@tonic-gate 			return;
6370Sstevel@tonic-gate 		cp = value(HOME);
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 	if (chdir(cp) < 0)
640*549Smuffin 		(void) printf("%s: bad directory\r\n", cp);
641*549Smuffin 	(void) printf("!\r\n");
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
644*549Smuffin void
645*549Smuffin tip_abort(char *msg)
6460Sstevel@tonic-gate {
647*549Smuffin 	/* don't want to hear about our child */
648*549Smuffin 	(void) signal(SIGCHLD, SIG_DFL);
649*549Smuffin 	(void) kill(pid, SIGTERM);
6500Sstevel@tonic-gate 	myperm();
6510Sstevel@tonic-gate 	disconnect(msg);
6520Sstevel@tonic-gate 	if (msg != NOSTR)
653*549Smuffin 		(void) printf("\r\n%s", msg);
654*549Smuffin 	(void) printf("\r\n[EOT]\r\n");
6550Sstevel@tonic-gate 	delock(uucplock);
6560Sstevel@tonic-gate 	unraw();
6570Sstevel@tonic-gate 	exit(0);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate 
660*549Smuffin /* ARGSUSED */
661*549Smuffin void
662*549Smuffin finish(int cc)
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate 	char *dismsg;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	if ((dismsg = value(DISCONNECT)) != NOSTR) {
667*549Smuffin 		(void) write(FD, dismsg, strlen(dismsg));
668*549Smuffin 		(void) sleep(5);
6690Sstevel@tonic-gate 	}
670*549Smuffin 	tip_abort(NOSTR);
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate void
674*549Smuffin intcopy(void)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate 
677*549Smuffin 	(void) signal(SIGINT, SIG_IGN);
6780Sstevel@tonic-gate 	siglongjmp(intbuf, 1);
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate 
681*549Smuffin void
682*549Smuffin execute(char *s)
6830Sstevel@tonic-gate {
684*549Smuffin 	char *cp;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	if ((cp = strrchr(value(SHELL), '/')) == NULL)
6870Sstevel@tonic-gate 		cp = value(SHELL);
6880Sstevel@tonic-gate 	else
6890Sstevel@tonic-gate 		cp++;
690*549Smuffin 	(void) execl(value(SHELL), cp, "-c", s, 0);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate 
693*549Smuffin int
694*549Smuffin args(char *buf, char *a[], size_t na)
6950Sstevel@tonic-gate {
696*549Smuffin 	char *p = buf, *start;
697*549Smuffin 	char **parg = a;
698*549Smuffin 	int n = 0;
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	do {
7010Sstevel@tonic-gate 		while (*p && (*p == ' ' || *p == '\t'))
7020Sstevel@tonic-gate 			p++;
7030Sstevel@tonic-gate 		start = p;
7040Sstevel@tonic-gate 		if (*p)
7050Sstevel@tonic-gate 			*parg = p;
7060Sstevel@tonic-gate 		while (*p && (*p != ' ' && *p != '\t'))
7070Sstevel@tonic-gate 			p++;
7080Sstevel@tonic-gate 		if (p != start)
7090Sstevel@tonic-gate 			parg++, n++;
7100Sstevel@tonic-gate 		if (*p)
7110Sstevel@tonic-gate 			*p++ = '\0';
7120Sstevel@tonic-gate 	} while (*p && n < na);
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	return (n);
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate 
717*549Smuffin void
718*549Smuffin prtime(char *s, time_t a)
7190Sstevel@tonic-gate {
720*549Smuffin 	int i;
7210Sstevel@tonic-gate 	int nums[3];
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	for (i = 0; i < 3; i++) {
7240Sstevel@tonic-gate 		nums[i] = (int)(a % quant[i]);
7250Sstevel@tonic-gate 		a /= quant[i];
7260Sstevel@tonic-gate 	}
727*549Smuffin 	(void) printf("%s", s);
7280Sstevel@tonic-gate 	while (--i >= 0)
7290Sstevel@tonic-gate 		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
730*549Smuffin 			(void) printf("%d %s%c ", nums[i], sep[i],
731*549Smuffin 			    nums[i] == 1 ? '\0' : 's');
732*549Smuffin 	(void) printf("\r\n!\r\n");
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
735*549Smuffin /* ARGSUSED */
736*549Smuffin void
737*549Smuffin variable(int cc)
7380Sstevel@tonic-gate {
7390Sstevel@tonic-gate 	char	buf[256];
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	if (prompt("[set] ", buf, sizeof (buf)))
7420Sstevel@tonic-gate 		return;
7430Sstevel@tonic-gate 	vlex(buf);
7440Sstevel@tonic-gate 	if (vtable[BEAUTIFY].v_access&CHANGED) {
7450Sstevel@tonic-gate 		vtable[BEAUTIFY].v_access &= ~CHANGED;
746*549Smuffin 		(void) kill(pid, SIGSYS);
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 	if (vtable[SCRIPT].v_access&CHANGED) {
7490Sstevel@tonic-gate 		vtable[SCRIPT].v_access &= ~CHANGED;
7500Sstevel@tonic-gate 		setscript();
7510Sstevel@tonic-gate 		/*
7520Sstevel@tonic-gate 		 * So that "set record=blah script" doesn't
7530Sstevel@tonic-gate 		 *  cause two transactions to occur.
7540Sstevel@tonic-gate 		 */
7550Sstevel@tonic-gate 		if (vtable[RECORD].v_access&CHANGED)
7560Sstevel@tonic-gate 			vtable[RECORD].v_access &= ~CHANGED;
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 	if (vtable[RECORD].v_access&CHANGED) {
7590Sstevel@tonic-gate 		vtable[RECORD].v_access &= ~CHANGED;
7600Sstevel@tonic-gate 		if (boolean(value(SCRIPT)))
7610Sstevel@tonic-gate 			setscript();
7620Sstevel@tonic-gate 	}
7630Sstevel@tonic-gate 	if (vtable[TAND].v_access&CHANGED) {
7640Sstevel@tonic-gate 		vtable[TAND].v_access &= ~CHANGED;
7650Sstevel@tonic-gate 		if (boolean(value(TAND)))
7660Sstevel@tonic-gate 			tandem("on");
7670Sstevel@tonic-gate 		else
7680Sstevel@tonic-gate 			tandem("off");
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 	if (vtable[LECHO].v_access&CHANGED) {
7710Sstevel@tonic-gate 		vtable[LECHO].v_access &= ~CHANGED;
7720Sstevel@tonic-gate 		boolean(value(HALFDUPLEX)) = boolean(value(LECHO));
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 	if (vtable[PARITY].v_access&CHANGED) {
7750Sstevel@tonic-gate 		vtable[PARITY].v_access &= ~CHANGED;
7760Sstevel@tonic-gate 		setparity(NULL);
7770Sstevel@tonic-gate 	}
7780Sstevel@tonic-gate 	if (vtable[BAUDRATE].v_access&CHANGED) {
7790Sstevel@tonic-gate 		vtable[BAUDRATE].v_access &= ~CHANGED;
7800Sstevel@tonic-gate 		ttysetup(speed(number(value(BAUDRATE))));
7810Sstevel@tonic-gate 	}
7820Sstevel@tonic-gate 	if (vtable[HARDWAREFLOW].v_access & CHANGED) {
7830Sstevel@tonic-gate 		vtable[HARDWAREFLOW].v_access &= ~CHANGED;
7840Sstevel@tonic-gate 		if (boolean(value(HARDWAREFLOW)))
7850Sstevel@tonic-gate 			hardwareflow("on");
7860Sstevel@tonic-gate 		else
7870Sstevel@tonic-gate 			hardwareflow("off");
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate /*
7920Sstevel@tonic-gate  * Turn tandem mode on or off for remote tty.
7930Sstevel@tonic-gate  */
794*549Smuffin void
795*549Smuffin tandem(char *option)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	struct termios rmtty;
7980Sstevel@tonic-gate 
799*549Smuffin 	(void) ioctl(FD, TCGETS, (char *)&rmtty);
8000Sstevel@tonic-gate 	if (equal(option, "on")) {
8010Sstevel@tonic-gate 		rmtty.c_iflag |= IXOFF|IXON;
8020Sstevel@tonic-gate 		arg.c_iflag |= IXOFF|IXON;
8030Sstevel@tonic-gate 		rmtty.c_cc[VSTART] = defarg.c_cc[VSTART];
8040Sstevel@tonic-gate 		rmtty.c_cc[VSTOP] = defarg.c_cc[VSTOP];
8050Sstevel@tonic-gate 	} else {
8060Sstevel@tonic-gate 		rmtty.c_iflag &= ~(IXOFF|IXON);
8070Sstevel@tonic-gate 		arg.c_iflag &= ~(IXOFF|IXON);
8080Sstevel@tonic-gate 	}
809*549Smuffin 	(void) ioctl(FD, TCSETSF, (char *)&rmtty);
810*549Smuffin 	(void) ioctl(0, TCSETSF, (char *)&arg);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate /*
8140Sstevel@tonic-gate  * Turn hardwareflow mode on or off for remote tty.
8150Sstevel@tonic-gate  */
816*549Smuffin void
817*549Smuffin hardwareflow(char *option)
8180Sstevel@tonic-gate {
8190Sstevel@tonic-gate 	struct termios rmtty;
8200Sstevel@tonic-gate 
821*549Smuffin 	(void) ioctl(FD, TCGETS, (char *)&rmtty);
8220Sstevel@tonic-gate 	if (equal(option, "on")) {
8230Sstevel@tonic-gate 		rmtty.c_cflag |= (CRTSCTS|CRTSXOFF);
8240Sstevel@tonic-gate 	} else {
8250Sstevel@tonic-gate 		rmtty.c_cflag &= ~(CRTSCTS|CRTSXOFF);
8260Sstevel@tonic-gate 	}
827*549Smuffin 	(void) ioctl(FD, TCSETSF, (char *)&rmtty);
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate /*
8310Sstevel@tonic-gate  * Turn interrupts from local tty on or off.
8320Sstevel@tonic-gate  */
833*549Smuffin void
834*549Smuffin intr(char *option)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	if (equal(option, "on"))
8380Sstevel@tonic-gate 		arg.c_lflag |= ISIG;
8390Sstevel@tonic-gate 	else
8400Sstevel@tonic-gate 		arg.c_lflag &= ~ISIG;
841*549Smuffin 	(void) ioctl(0, TCSETSF, (char *)&arg);
8420Sstevel@tonic-gate }
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate /*
8450Sstevel@tonic-gate  * Send a break.
8460Sstevel@tonic-gate  */
847*549Smuffin /* ARGSUSED */
848*549Smuffin void
849*549Smuffin genbrk(int cc)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 
852*549Smuffin 	(void) ioctl(FD, TCSBRK, 0);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate /*
8560Sstevel@tonic-gate  * Suspend tip
8570Sstevel@tonic-gate  */
858*549Smuffin void
859*549Smuffin suspend(int c)
8600Sstevel@tonic-gate {
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	unraw();
863*549Smuffin 	(void) kill(c == _CTRL('y') ? getpid() : 0, SIGTSTP);
8640Sstevel@tonic-gate 	raw();
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate  *	expand a file name if it includes shell meta characters
8690Sstevel@tonic-gate  */
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate char *
872*549Smuffin expand(char name[])
8730Sstevel@tonic-gate {
8740Sstevel@tonic-gate 	static char xname[BUFSIZ];
8750Sstevel@tonic-gate 	char cmdbuf[BUFSIZ];
876*549Smuffin 	int pid, l;
877*549Smuffin 	char *cp, *Shell;
8780Sstevel@tonic-gate 	int s, pivec[2];
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	if (!anyof(name, "~{[*?$`'\"\\"))
8810Sstevel@tonic-gate 		return (name);
8820Sstevel@tonic-gate 	if (pipe(pivec) < 0) {
8830Sstevel@tonic-gate 		perror("pipe");
8840Sstevel@tonic-gate 		return (name);
8850Sstevel@tonic-gate 	}
886*549Smuffin 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "echo %s", name);
8870Sstevel@tonic-gate 	if ((pid = vfork()) == 0) {
8880Sstevel@tonic-gate 		userperm();
8890Sstevel@tonic-gate 		Shell = value(SHELL);
8900Sstevel@tonic-gate 		if (Shell == NOSTR)
8910Sstevel@tonic-gate 			Shell = "/bin/sh";
892*549Smuffin 		(void) close(pivec[0]);
893*549Smuffin 		(void) close(1);
894*549Smuffin 		(void) dup(pivec[1]);
895*549Smuffin 		(void) close(pivec[1]);
896*549Smuffin 		(void) close(2);
897*549Smuffin 		(void) execl(Shell, Shell, "-c", cmdbuf, 0);
8980Sstevel@tonic-gate 		_exit(1);
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 	if (pid == -1) {
9010Sstevel@tonic-gate 		perror("fork");
902*549Smuffin 		(void) close(pivec[0]);
903*549Smuffin 		(void) close(pivec[1]);
9040Sstevel@tonic-gate 		return (NOSTR);
9050Sstevel@tonic-gate 	}
906*549Smuffin 	(void) close(pivec[1]);
9070Sstevel@tonic-gate 	l = read(pivec[0], xname, BUFSIZ);
908*549Smuffin 	(void) close(pivec[0]);
909*549Smuffin 	while (wait(&s) != pid)
9100Sstevel@tonic-gate 		;
9110Sstevel@tonic-gate 	s &= 0377;
9120Sstevel@tonic-gate 	if (s != 0 && s != SIGPIPE) {
913*549Smuffin 		(void) fprintf(stderr, "\"Echo\" failed\n");
9140Sstevel@tonic-gate 		return (NOSTR);
9150Sstevel@tonic-gate 	}
9160Sstevel@tonic-gate 	if (l < 0) {
9170Sstevel@tonic-gate 		perror("read");
9180Sstevel@tonic-gate 		return (NOSTR);
9190Sstevel@tonic-gate 	}
9200Sstevel@tonic-gate 	if (l == 0) {
921*549Smuffin 		(void) fprintf(stderr, "\"%s\": No match\n", name);
9220Sstevel@tonic-gate 		return (NOSTR);
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 	if (l == BUFSIZ) {
925*549Smuffin 		(void) fprintf(stderr, "Buffer overflow expanding \"%s\"\n",
926*549Smuffin 		    name);
9270Sstevel@tonic-gate 		return (NOSTR);
9280Sstevel@tonic-gate 	}
9290Sstevel@tonic-gate 	xname[l] = 0;
9300Sstevel@tonic-gate 	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
9310Sstevel@tonic-gate 		;
9320Sstevel@tonic-gate 	*++cp = '\0';
9330Sstevel@tonic-gate 	return (xname);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate  * Are any of the characters in the two strings the same?
9380Sstevel@tonic-gate  */
9390Sstevel@tonic-gate 
940*549Smuffin int
941*549Smuffin anyof(char *s1, char *s2)
9420Sstevel@tonic-gate {
943*549Smuffin 	int c;
9440Sstevel@tonic-gate 
945*549Smuffin 	while ((c = *s1++) != 0)
9460Sstevel@tonic-gate 		if (any(c, s2))
9470Sstevel@tonic-gate 			return (1);
9480Sstevel@tonic-gate 	return (0);
9490Sstevel@tonic-gate }
950