xref: /illumos-gate/usr/src/cmd/tip/cmds.c (revision 1e094e1b)
17c478bd9Sstevel@tonic-gate /*
294e1761eSsn  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
58d489c7aSmuffin 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
87c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
97c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
107c478bd9Sstevel@tonic-gate  */
117c478bd9Sstevel@tonic-gate 
127c478bd9Sstevel@tonic-gate #include "tip.h"
1394e1761eSsn #include <limits.h>
147c478bd9Sstevel@tonic-gate #ifdef USG
157c478bd9Sstevel@tonic-gate #include <unistd.h>
167c478bd9Sstevel@tonic-gate #else
177c478bd9Sstevel@tonic-gate #include <vfork.h>
187c478bd9Sstevel@tonic-gate #endif
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate /*
217c478bd9Sstevel@tonic-gate  * tip
227c478bd9Sstevel@tonic-gate  *
237c478bd9Sstevel@tonic-gate  * miscellaneous commands
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26*1e094e1bSToomas Soome struct termios arg;
27*1e094e1bSToomas Soome struct termios defarg;
28*1e094e1bSToomas Soome int	FD;
29*1e094e1bSToomas Soome int	fildes[2];
30*1e094e1bSToomas Soome int	repdes[2];
31*1e094e1bSToomas Soome int	pid;
32*1e094e1bSToomas Soome int	sfd;
33*1e094e1bSToomas Soome int	stoprompt;
34*1e094e1bSToomas Soome int	timedout;
357c478bd9Sstevel@tonic-gate int	quant[] = { 60, 60, 24 };
367c478bd9Sstevel@tonic-gate 
37*1e094e1bSToomas Soome char	copyname[80];
38*1e094e1bSToomas Soome char	fname[80];
39*1e094e1bSToomas Soome char	ccc;
407c478bd9Sstevel@tonic-gate char	null = '\0';
417c478bd9Sstevel@tonic-gate char	*sep[] = { "second", "minute", "hour" };
427c478bd9Sstevel@tonic-gate static	char *argv[10];		/* argument vector for take and put */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate sigjmp_buf intbuf;		/* for interrupts and timeouts */
457c478bd9Sstevel@tonic-gate 
468d489c7aSmuffin void	timeout(void);		/* timeout function called on alarm */
478d489c7aSmuffin void	intcopy(void);		/* interrupt routine for file transfers */
488d489c7aSmuffin void	transfer(char *, int, char *);
498d489c7aSmuffin void	transmit(FILE *, char *, char *);
508d489c7aSmuffin void	send(char);
518d489c7aSmuffin void	execute(char *);
528d489c7aSmuffin void	prtime(char *, time_t);
538d489c7aSmuffin void	hardwareflow(char *);
548d489c7aSmuffin void	intr(char *);
558d489c7aSmuffin int	args(char *, char *[], size_t);
568d489c7aSmuffin int	anyof(char *, char *);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * FTP - remote ==> local
607c478bd9Sstevel@tonic-gate  *  get a file from the remote host
617c478bd9Sstevel@tonic-gate  */
628d489c7aSmuffin void
getfl(int c)638d489c7aSmuffin getfl(int c)
647c478bd9Sstevel@tonic-gate {
658d489c7aSmuffin 	char buf[256], *cp;
667c478bd9Sstevel@tonic-gate 
678d489c7aSmuffin 	(void) putchar(c);
687c478bd9Sstevel@tonic-gate 	/*
697c478bd9Sstevel@tonic-gate 	 * get the UNIX receiving file's name
707c478bd9Sstevel@tonic-gate 	 */
717c478bd9Sstevel@tonic-gate 	if (prompt("Local file name? ", copyname, sizeof (copyname)))
727c478bd9Sstevel@tonic-gate 		return;
737c478bd9Sstevel@tonic-gate 	cp = expand(copyname);
747c478bd9Sstevel@tonic-gate 	if (cp == NOSTR)
757c478bd9Sstevel@tonic-gate 		return;
767c478bd9Sstevel@tonic-gate 	if ((sfd = creat(cp, 0666)) < 0) {
778d489c7aSmuffin 		(void) printf("\r\n%s: cannot creat\r\n", copyname);
787c478bd9Sstevel@tonic-gate 		return;
797c478bd9Sstevel@tonic-gate 	}
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	/*
827c478bd9Sstevel@tonic-gate 	 * collect parameters
837c478bd9Sstevel@tonic-gate 	 */
847c478bd9Sstevel@tonic-gate 	if (prompt("List command for remote system? ", buf, sizeof (buf))) {
858d489c7aSmuffin 		(void) unlink(copyname);
867c478bd9Sstevel@tonic-gate 		return;
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 	transfer(buf, sfd, value(EOFREAD));
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * Cu-like take command
937c478bd9Sstevel@tonic-gate  */
948d489c7aSmuffin /* ARGSUSED */
958d489c7aSmuffin void
cu_take(int cc)968d489c7aSmuffin cu_take(int cc)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	int fd, argc;
998d489c7aSmuffin 	char line[BUFSIZ], *cp;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if (prompt("[take] ", copyname, sizeof (copyname)))
1027c478bd9Sstevel@tonic-gate 		return;
1037c478bd9Sstevel@tonic-gate 	argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
1047c478bd9Sstevel@tonic-gate 	if (argc < 1 || argc > 2) {
1058d489c7aSmuffin 		(void) printf("usage: <take> from [to]\r\n");
1067c478bd9Sstevel@tonic-gate 		return;
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 	if (argc == 1)
1097c478bd9Sstevel@tonic-gate 		argv[1] = argv[0];
1107c478bd9Sstevel@tonic-gate 	cp = expand(argv[1]);
1117c478bd9Sstevel@tonic-gate 	if (cp == NOSTR)
1127c478bd9Sstevel@tonic-gate 		return;
1137c478bd9Sstevel@tonic-gate 	if ((fd = creat(cp, 0666)) < 0) {
1148d489c7aSmuffin 		(void) printf("\r\n%s: cannot create\r\n", argv[1]);
1157c478bd9Sstevel@tonic-gate 		return;
1167c478bd9Sstevel@tonic-gate 	}
1178d489c7aSmuffin 	(void) snprintf(line, sizeof (line), "cat %s; echo \01", argv[0]);
1187c478bd9Sstevel@tonic-gate 	transfer(line, fd, "\01");
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Bulk transfer routine --
1237c478bd9Sstevel@tonic-gate  *  used by getfl(), cu_take(), and pipefile()
1247c478bd9Sstevel@tonic-gate  */
1258d489c7aSmuffin void
transfer(char * buf,int fd,char * eofchars)1268d489c7aSmuffin transfer(char *buf, int fd, char *eofchars)
1277c478bd9Sstevel@tonic-gate {
1288d489c7aSmuffin 	int ct;
1297c478bd9Sstevel@tonic-gate 	char c, buffer[BUFSIZ];
1307c478bd9Sstevel@tonic-gate 	char *p = buffer;	/* can't be register because of longjmp */
1318d489c7aSmuffin 	int cnt, eof, bol;
1327c478bd9Sstevel@tonic-gate 	time_t start;
1338d489c7aSmuffin 	sig_handler_t	f;
1347c478bd9Sstevel@tonic-gate 
1358d489c7aSmuffin 	parwrite(FD, (unsigned char *)buf, strlen(buf));
1368d489c7aSmuffin 	(void) kill(pid, SIGIOT);
1378d489c7aSmuffin 	/* Wait until read process stops */
1388d489c7aSmuffin 	(void) read(repdes[0], (char *)&ccc, 1);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	/*
1417c478bd9Sstevel@tonic-gate 	 * finish command
1427c478bd9Sstevel@tonic-gate 	 */
1438d489c7aSmuffin 	parwrite(FD, (unsigned char *)"\r", 1);
1447c478bd9Sstevel@tonic-gate 	do
1458d489c7aSmuffin 		(void) read(FD, &c, 1);
1468d489c7aSmuffin 	while ((c&0177) != '\n')
1478d489c7aSmuffin 		;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	if (sigsetjmp(intbuf, 1))
1507c478bd9Sstevel@tonic-gate 		goto out;
1518d489c7aSmuffin 	f = signal(SIGINT, (sig_handler_t)intcopy);
1527c478bd9Sstevel@tonic-gate 	intr("on");
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	start = time(0);
1557c478bd9Sstevel@tonic-gate 	bol = 1;
1567c478bd9Sstevel@tonic-gate 	ct = 0;
1577c478bd9Sstevel@tonic-gate 	for (;;) {
1587c478bd9Sstevel@tonic-gate 		eof = read(FD, &c, 1) <= 0;
1597c478bd9Sstevel@tonic-gate 		if (noparity)
1607c478bd9Sstevel@tonic-gate 			c &= 0377;
1617c478bd9Sstevel@tonic-gate 		else
1627c478bd9Sstevel@tonic-gate 			c &= 0177;
1637c478bd9Sstevel@tonic-gate 		if (eof || (bol && any(c, eofchars)))
1647c478bd9Sstevel@tonic-gate 			break;
1657c478bd9Sstevel@tonic-gate 		if (c == 0)
1667c478bd9Sstevel@tonic-gate 			continue;	/* ignore nulls */
1677c478bd9Sstevel@tonic-gate 		if (c == '\r')
1687c478bd9Sstevel@tonic-gate 			continue;
1697c478bd9Sstevel@tonic-gate 		*p++ = c;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		if (c == '\n') {
1727c478bd9Sstevel@tonic-gate 			bol = 1;
1737c478bd9Sstevel@tonic-gate 			if (boolean(value(VERBOSE)))
1748d489c7aSmuffin 				(void) printf("\r%d", ++ct);
1757c478bd9Sstevel@tonic-gate 		} else
1767c478bd9Sstevel@tonic-gate 			bol = 0;
1777c478bd9Sstevel@tonic-gate 		if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
1787c478bd9Sstevel@tonic-gate 			if (write(fd, buffer, cnt) != cnt) {
1798d489c7aSmuffin 				(void) printf("\r\nwrite error\r\n");
1807c478bd9Sstevel@tonic-gate 				goto out;
1817c478bd9Sstevel@tonic-gate 			}
1827c478bd9Sstevel@tonic-gate 			p = buffer;
1837c478bd9Sstevel@tonic-gate 		}
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate out:
1868d489c7aSmuffin 	if ((cnt = (p-buffer)) != 0)
1877c478bd9Sstevel@tonic-gate 		if (write(fd, buffer, cnt) != cnt)
1888d489c7aSmuffin 			(void) printf("\r\nwrite error\r\n");
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
1917c478bd9Sstevel@tonic-gate 		prtime(" lines transferred in ", time(0)-start);
1927c478bd9Sstevel@tonic-gate 	intr("off");
1938d489c7aSmuffin 	(void) write(fildes[1], (char *)&ccc, 1);
1948d489c7aSmuffin 	(void) signal(SIGINT, f);
1958d489c7aSmuffin 	(void) close(fd);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate  * FTP - remote ==> local process
2007c478bd9Sstevel@tonic-gate  *   send remote input to local process via pipe
2017c478bd9Sstevel@tonic-gate  */
2028d489c7aSmuffin /* ARGSUSED */
2038d489c7aSmuffin void
pipefile(int cc)2048d489c7aSmuffin pipefile(int cc)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	int cpid, pdes[2];
2077c478bd9Sstevel@tonic-gate 	char buf[256];
2087c478bd9Sstevel@tonic-gate 	int status, p;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (prompt("Local command? ", buf, sizeof (buf)))
2117c478bd9Sstevel@tonic-gate 		return;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	if (pipe(pdes)) {
2148d489c7aSmuffin 		(void) printf("can't establish pipe\r\n");
2157c478bd9Sstevel@tonic-gate 		return;
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if ((cpid = fork()) < 0) {
2198d489c7aSmuffin 		(void) printf("can't fork!\r\n");
2207c478bd9Sstevel@tonic-gate 		return;
2217c478bd9Sstevel@tonic-gate 	} else if (cpid) {
2227c478bd9Sstevel@tonic-gate 		if (prompt("List command for remote system? ", buf,
2238d489c7aSmuffin 		    sizeof (buf))) {
2248d489c7aSmuffin 			(void) close(pdes[0]), (void) close(pdes[1]);
2258d489c7aSmuffin 			(void) kill(cpid, SIGKILL);
2267c478bd9Sstevel@tonic-gate 		} else {
2278d489c7aSmuffin 			(void) close(pdes[0]);
2288d489c7aSmuffin 			(void) signal(SIGPIPE, (sig_handler_t)intcopy);
2297c478bd9Sstevel@tonic-gate 			transfer(buf, pdes[1], value(EOFREAD));
2308d489c7aSmuffin 			(void) signal(SIGPIPE, SIG_DFL);
2317c478bd9Sstevel@tonic-gate 			while ((p = wait(&status)) > 0 && p != cpid)
2327c478bd9Sstevel@tonic-gate 				;
2337c478bd9Sstevel@tonic-gate 		}
2347c478bd9Sstevel@tonic-gate 	} else {
2358d489c7aSmuffin 		int f;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 		userperm();
2388d489c7aSmuffin 		(void) dup2(pdes[0], 0);
2398d489c7aSmuffin 		(void) close(pdes[0]);
2407c478bd9Sstevel@tonic-gate 		for (f = 3; f < 20; f++)
2418d489c7aSmuffin 			(void) close(f);
2427c478bd9Sstevel@tonic-gate 		execute(buf);
2438d489c7aSmuffin 		(void) printf("can't execl!\r\n");
2447c478bd9Sstevel@tonic-gate 		exit(0);
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * FTP - local ==> remote
2507c478bd9Sstevel@tonic-gate  *  send local file to remote host
2517c478bd9Sstevel@tonic-gate  *  terminate transmission with pseudo EOF sequence
2527c478bd9Sstevel@tonic-gate  */
2538d489c7aSmuffin void
tip_sendfile(int cc)2548d489c7aSmuffin tip_sendfile(int cc)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	FILE *fd;
2577c478bd9Sstevel@tonic-gate 	char *fnamex;
2587c478bd9Sstevel@tonic-gate 
2598d489c7aSmuffin 	(void) putchar(cc);
2607c478bd9Sstevel@tonic-gate 	/*
2617c478bd9Sstevel@tonic-gate 	 * get file name
2627c478bd9Sstevel@tonic-gate 	 */
2637c478bd9Sstevel@tonic-gate 	if (prompt("Local file name? ", fname, sizeof (fname)))
2647c478bd9Sstevel@tonic-gate 		return;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	/*
2677c478bd9Sstevel@tonic-gate 	 * look up file
2687c478bd9Sstevel@tonic-gate 	 */
2697c478bd9Sstevel@tonic-gate 	fnamex = expand(fname);
2707c478bd9Sstevel@tonic-gate 	if (fnamex == NOSTR)
2717c478bd9Sstevel@tonic-gate 		return;
2727c478bd9Sstevel@tonic-gate 	if ((fd = fopen(fnamex, "r")) == NULL) {
2738d489c7aSmuffin 		(void) printf("%s: cannot open\r\n", fname);
2747c478bd9Sstevel@tonic-gate 		return;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 	transmit(fd, value(EOFWRITE), NULL);
2777c478bd9Sstevel@tonic-gate 	if (!boolean(value(ECHOCHECK))) {
2787c478bd9Sstevel@tonic-gate 		struct termios buf;
2797c478bd9Sstevel@tonic-gate 
2808d489c7aSmuffin 		(void) ioctl(FD, TCGETS, (char *)&buf);	/* this does a */
2818d489c7aSmuffin 		(void) ioctl(FD, TCSETSF, (char *)&buf);	/* wflushtty */
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate /*
2867c478bd9Sstevel@tonic-gate  * Bulk transfer routine to remote host --
2878d489c7aSmuffin  *   used by tip_sendfile() and cu_put()
2887c478bd9Sstevel@tonic-gate  */
2898d489c7aSmuffin void
transmit(FILE * fd,char * eofchars,char * command)2908d489c7aSmuffin transmit(FILE *fd, char *eofchars, char *command)
2917c478bd9Sstevel@tonic-gate {
2928d489c7aSmuffin 	sig_handler_t	ointr;
2937c478bd9Sstevel@tonic-gate 	char *pc, lastc, rc;
2947c478bd9Sstevel@tonic-gate 	int c, ccount, lcount;
2957c478bd9Sstevel@tonic-gate 	time_t start_t, stop_t;
2967c478bd9Sstevel@tonic-gate 
2978d489c7aSmuffin 	(void) kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
2987c478bd9Sstevel@tonic-gate 	timedout = 0;
2997c478bd9Sstevel@tonic-gate 	if (sigsetjmp(intbuf, 1)) {
3007c478bd9Sstevel@tonic-gate 		if (timedout)
3018d489c7aSmuffin 			(void) printf("\r\ntimed out at eol\r\n");
3028d489c7aSmuffin 		(void) alarm(0);
3037c478bd9Sstevel@tonic-gate 		goto out;
3047c478bd9Sstevel@tonic-gate 	}
3058d489c7aSmuffin 	ointr = signal(SIGINT, (sig_handler_t)intcopy);
3067c478bd9Sstevel@tonic-gate 	intr("on");
3078d489c7aSmuffin 	(void) read(repdes[0], (char *)&ccc, 1);
3087c478bd9Sstevel@tonic-gate 	if (command != NULL) {
3097c478bd9Sstevel@tonic-gate 		for (pc = command; *pc; pc++)
3107c478bd9Sstevel@tonic-gate 			send(*pc);
3117c478bd9Sstevel@tonic-gate 		if (boolean(value(ECHOCHECK)))
3128d489c7aSmuffin 			(void) read(FD, (char *)&c, 1);	/* trailing \n */
3137c478bd9Sstevel@tonic-gate 		else {
3147c478bd9Sstevel@tonic-gate 			struct termios buf;
3158d489c7aSmuffin 			/* wait for remote stty to take effect */
3168d489c7aSmuffin 			(void) sleep(5);
3178d489c7aSmuffin 			/* this does a */
3188d489c7aSmuffin 			(void) ioctl(FD, TCGETS, (char *)&buf);
3198d489c7aSmuffin 			/* wflushtty */
3208d489c7aSmuffin 			(void) ioctl(FD, TCSETSF, (char *)&buf);
3217c478bd9Sstevel@tonic-gate 		}
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 	lcount = 0;
3247c478bd9Sstevel@tonic-gate 	lastc = '\0';
3257c478bd9Sstevel@tonic-gate 	start_t = time(0);
3267c478bd9Sstevel@tonic-gate 	if (boolean(value(RAWFTP))) {
3277c478bd9Sstevel@tonic-gate 		while ((c = getc(fd)) != EOF) {
3287c478bd9Sstevel@tonic-gate 			lcount++;
3297c478bd9Sstevel@tonic-gate 			send(c);
3307c478bd9Sstevel@tonic-gate 			if (boolean(value(VERBOSE)) && lcount%100 == 0)
3318d489c7aSmuffin 				(void) printf("\r%d", lcount);
3327c478bd9Sstevel@tonic-gate 		}
3337c478bd9Sstevel@tonic-gate 		if (boolean(value(VERBOSE)))
3348d489c7aSmuffin 			(void) printf("\r%d", lcount);
3357c478bd9Sstevel@tonic-gate 		goto out;
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 	for (;;) {
3387c478bd9Sstevel@tonic-gate 		ccount = 0;
3397c478bd9Sstevel@tonic-gate 		do {
3407c478bd9Sstevel@tonic-gate 			c = getc(fd);
3417c478bd9Sstevel@tonic-gate 			if (c == EOF)
3427c478bd9Sstevel@tonic-gate 				goto out;
3437c478bd9Sstevel@tonic-gate 			if (c == 0177)
3447c478bd9Sstevel@tonic-gate 				continue;
3457c478bd9Sstevel@tonic-gate 			lastc = c;
3467c478bd9Sstevel@tonic-gate 			if (c < 040) {
3477c478bd9Sstevel@tonic-gate 				if (c == '\n') {
3487c478bd9Sstevel@tonic-gate 					c = '\r';
3497c478bd9Sstevel@tonic-gate 				} else if (c == '\t') {
3507c478bd9Sstevel@tonic-gate 					if (boolean(value(TABEXPAND))) {
3517c478bd9Sstevel@tonic-gate 						send(' ');
3527c478bd9Sstevel@tonic-gate 						while ((++ccount % 8) != 0)
3537c478bd9Sstevel@tonic-gate 							send(' ');
3547c478bd9Sstevel@tonic-gate 						continue;
3557c478bd9Sstevel@tonic-gate 					}
3567c478bd9Sstevel@tonic-gate 				} else
3577c478bd9Sstevel@tonic-gate 					continue;
3587c478bd9Sstevel@tonic-gate 			}
3597c478bd9Sstevel@tonic-gate 			send(c);
3607c478bd9Sstevel@tonic-gate 		} while (c != '\r');
3617c478bd9Sstevel@tonic-gate 		if (boolean(value(VERBOSE)))
3628d489c7aSmuffin 			(void) printf("\r%d", ++lcount);
3637c478bd9Sstevel@tonic-gate 		if (boolean(value(ECHOCHECK))) {
3648d489c7aSmuffin 			(void) alarm(number(value(ETIMEOUT)));
3657c478bd9Sstevel@tonic-gate 			do {	/* wait for prompt */
3668d489c7aSmuffin 				(void) read(FD, &rc, 1);
3677c478bd9Sstevel@tonic-gate 			} while ((rc&0177) != character(value(PROMPT)));
3688d489c7aSmuffin 			(void) alarm(0);
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate out:
3727c478bd9Sstevel@tonic-gate 	if (lastc != '\n' && !boolean(value(RAWFTP)))
3737c478bd9Sstevel@tonic-gate 		send('\r');
3747c478bd9Sstevel@tonic-gate 	if (eofchars)
3757c478bd9Sstevel@tonic-gate 		for (pc = eofchars; *pc; pc++)
3767c478bd9Sstevel@tonic-gate 			send(*pc);
3777c478bd9Sstevel@tonic-gate 	stop_t = time(0);
3788d489c7aSmuffin 	(void) fclose(fd);
3797c478bd9Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
3807c478bd9Sstevel@tonic-gate 		if (boolean(value(RAWFTP)))
3817c478bd9Sstevel@tonic-gate 			prtime(" chars transferred in ", stop_t-start_t);
3827c478bd9Sstevel@tonic-gate 		else
3837c478bd9Sstevel@tonic-gate 			prtime(" lines transferred in ", stop_t-start_t);
3848d489c7aSmuffin 	(void) write(fildes[1], (char *)&ccc, 1);
3857c478bd9Sstevel@tonic-gate 	intr("off");
3868d489c7aSmuffin 	(void) signal(SIGINT, ointr);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * Cu-like put command
3917c478bd9Sstevel@tonic-gate  */
3928d489c7aSmuffin /* ARGSUSED */
3938d489c7aSmuffin void
cu_put(int cc)3948d489c7aSmuffin cu_put(int cc)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	FILE *fd;
3977c478bd9Sstevel@tonic-gate 	char line[BUFSIZ];
3987c478bd9Sstevel@tonic-gate 	int argc;
3997c478bd9Sstevel@tonic-gate 	char *copynamex;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if (prompt("[put] ", copyname, sizeof (copyname)))
4027c478bd9Sstevel@tonic-gate 		return;
4037c478bd9Sstevel@tonic-gate 	argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
4047c478bd9Sstevel@tonic-gate 	if (argc < 1 || argc > 2) {
4058d489c7aSmuffin 		(void) printf("usage: <put> from [to]\r\n");
4067c478bd9Sstevel@tonic-gate 		return;
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 	if (argc == 1)
4097c478bd9Sstevel@tonic-gate 		argv[1] = argv[0];
4107c478bd9Sstevel@tonic-gate 	copynamex = expand(argv[0]);
4117c478bd9Sstevel@tonic-gate 	if (copynamex == NOSTR)
4127c478bd9Sstevel@tonic-gate 		return;
4137c478bd9Sstevel@tonic-gate 	if ((fd = fopen(copynamex, "r")) == NULL) {
4148d489c7aSmuffin 		(void) printf("%s: cannot open\r\n", copynamex);
4157c478bd9Sstevel@tonic-gate 		return;
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 	if (boolean(value(ECHOCHECK)))
4188d489c7aSmuffin 		(void) snprintf(line, sizeof (line), "cat>%s\r", argv[1]);
4197c478bd9Sstevel@tonic-gate 	else
4208d489c7aSmuffin 		(void) snprintf(line, sizeof (line),
4218d489c7aSmuffin 		    "stty -echo; cat>%s; stty echo\r", argv[1]);
4227c478bd9Sstevel@tonic-gate 	transmit(fd, "\04", line);
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  * FTP - send single character
4277c478bd9Sstevel@tonic-gate  *  wait for echo & handle timeout
4287c478bd9Sstevel@tonic-gate  */
4298d489c7aSmuffin void
send(char c)4308d489c7aSmuffin send(char c)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 	char cc;
4337c478bd9Sstevel@tonic-gate 	int retry = 0;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	cc = c;
4368d489c7aSmuffin 	parwrite(FD, (unsigned char *)&cc, 1);
4377c478bd9Sstevel@tonic-gate #ifdef notdef
4387c478bd9Sstevel@tonic-gate 	if (number(value(CDELAY)) > 0 && c != '\r')
4397c478bd9Sstevel@tonic-gate 		nap(number(value(CDELAY)));
4407c478bd9Sstevel@tonic-gate #endif
4417c478bd9Sstevel@tonic-gate 	if (!boolean(value(ECHOCHECK))) {
4427c478bd9Sstevel@tonic-gate #ifdef notdef
4437c478bd9Sstevel@tonic-gate 		if (number(value(LDELAY)) > 0 && c == '\r')
4447c478bd9Sstevel@tonic-gate 			nap(number(value(LDELAY)));
4457c478bd9Sstevel@tonic-gate #endif
4467c478bd9Sstevel@tonic-gate 		return;
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate tryagain:
4497c478bd9Sstevel@tonic-gate 	timedout = 0;
4507c478bd9Sstevel@tonic-gate 	if (sigsetjmp(intbuf, 1) && timedout) {
4518d489c7aSmuffin 		(void) printf("\r\ntimeout error (%s)\r\n", ctrl(c));
4527c478bd9Sstevel@tonic-gate 		if (retry++ > 3)
4537c478bd9Sstevel@tonic-gate 			return;
4548d489c7aSmuffin 		parwrite(FD, (unsigned char *)&null, 1); /* poke it */
4557c478bd9Sstevel@tonic-gate 		goto tryagain;
4567c478bd9Sstevel@tonic-gate 	}
4578d489c7aSmuffin 	(void) alarm(number(value(ETIMEOUT)));
4588d489c7aSmuffin 	(void) read(FD, &cc, 1);
4598d489c7aSmuffin 	(void) alarm(0);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate void
timeout(void)4638d489c7aSmuffin timeout(void)
4647c478bd9Sstevel@tonic-gate {
4658d489c7aSmuffin 	(void) signal(SIGALRM, (sig_handler_t)timeout);
4667c478bd9Sstevel@tonic-gate 	timedout = 1;
4677c478bd9Sstevel@tonic-gate 	siglongjmp(intbuf, 1);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate /*
4717c478bd9Sstevel@tonic-gate  * Stolen from consh() -- puts a remote file on the output of a local command.
4727c478bd9Sstevel@tonic-gate  *	Identical to consh() except for where stdout goes.
4737c478bd9Sstevel@tonic-gate  */
4748d489c7aSmuffin void
pipeout(int c)4758d489c7aSmuffin pipeout(int c)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	char buf[256];
4787c478bd9Sstevel@tonic-gate 	int cpid, status, p;
4797c478bd9Sstevel@tonic-gate 	time_t start;
4807c478bd9Sstevel@tonic-gate 
4818d489c7aSmuffin 	(void) putchar(c);
4827c478bd9Sstevel@tonic-gate 	if (prompt("Local command? ", buf, sizeof (buf)))
4837c478bd9Sstevel@tonic-gate 		return;
4848d489c7aSmuffin 	(void) kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
4858d489c7aSmuffin 	(void) signal(SIGINT, SIG_IGN);
4868d489c7aSmuffin 	(void) signal(SIGQUIT, SIG_IGN);
4877c478bd9Sstevel@tonic-gate 	intr("on");
4888d489c7aSmuffin 	(void) read(repdes[0], (char *)&ccc, 1);
4897c478bd9Sstevel@tonic-gate 	/*
4907c478bd9Sstevel@tonic-gate 	 * Set up file descriptors in the child and
4917c478bd9Sstevel@tonic-gate 	 *  let it go...
4927c478bd9Sstevel@tonic-gate 	 */
4937c478bd9Sstevel@tonic-gate 	if ((cpid = fork()) < 0)
4948d489c7aSmuffin 		(void) printf("can't fork!\r\n");
4957c478bd9Sstevel@tonic-gate 	else if (cpid) {
4967c478bd9Sstevel@tonic-gate 		start = time(0);
4977c478bd9Sstevel@tonic-gate 		while ((p = wait(&status)) > 0 && p != cpid)
4987c478bd9Sstevel@tonic-gate 			;
4997c478bd9Sstevel@tonic-gate 	} else {
5008d489c7aSmuffin 		int i;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		userperm();
5038d489c7aSmuffin 		(void) dup2(FD, 1);
5047c478bd9Sstevel@tonic-gate 		for (i = 3; i < 20; i++)
5058d489c7aSmuffin 			(void) close(i);
5068d489c7aSmuffin 		(void) signal(SIGINT, SIG_DFL);
5078d489c7aSmuffin 		(void) signal(SIGQUIT, SIG_DFL);
5087c478bd9Sstevel@tonic-gate 		execute(buf);
5098d489c7aSmuffin 		(void) printf("can't find `%s'\r\n", buf);
5107c478bd9Sstevel@tonic-gate 		exit(0);
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
5137c478bd9Sstevel@tonic-gate 		prtime("away for ", time(0)-start);
5148d489c7aSmuffin 	(void) write(fildes[1], (char *)&ccc, 1);
5157c478bd9Sstevel@tonic-gate 	intr("off");
5168d489c7aSmuffin 	(void) signal(SIGINT, SIG_DFL);
5178d489c7aSmuffin 	(void) signal(SIGQUIT, SIG_DFL);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate  * Fork a program with:
5227c478bd9Sstevel@tonic-gate  *  0 <-> remote tty in
5237c478bd9Sstevel@tonic-gate  *  1 <-> remote tty out
5247c478bd9Sstevel@tonic-gate  *  2 <-> local tty stderr out
5257c478bd9Sstevel@tonic-gate  */
5268d489c7aSmuffin void
consh(int c)5278d489c7aSmuffin consh(int c)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate 	char buf[256];
5307c478bd9Sstevel@tonic-gate 	int cpid, status, p;
5318d489c7aSmuffin 	sig_handler_t	ointr, oquit;
5327c478bd9Sstevel@tonic-gate 	time_t start;
5337c478bd9Sstevel@tonic-gate 
5348d489c7aSmuffin 	(void) putchar(c);
5357c478bd9Sstevel@tonic-gate 	if (prompt("Local command? ", buf, sizeof (buf)))
5367c478bd9Sstevel@tonic-gate 		return;
5378d489c7aSmuffin 	(void) kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
5388d489c7aSmuffin 	(void) read(repdes[0], (char *)&ccc, 1);
5397c478bd9Sstevel@tonic-gate 	ointr = signal(SIGINT, SIG_IGN);
5407c478bd9Sstevel@tonic-gate 	oquit = signal(SIGQUIT, SIG_IGN);
5417c478bd9Sstevel@tonic-gate 	unraw();
5427c478bd9Sstevel@tonic-gate 	/*
5437c478bd9Sstevel@tonic-gate 	 * Set up file descriptors in the child and
5447c478bd9Sstevel@tonic-gate 	 *  let it go...
5457c478bd9Sstevel@tonic-gate 	 */
5467c478bd9Sstevel@tonic-gate 	if ((cpid = fork()) < 0)
5478d489c7aSmuffin 		(void) printf("can't fork!\r\n");
5487c478bd9Sstevel@tonic-gate 	else if (cpid) {
5497c478bd9Sstevel@tonic-gate 		start = time(0);
5507c478bd9Sstevel@tonic-gate 		while ((p = wait(&status)) > 0 && p != cpid)
5517c478bd9Sstevel@tonic-gate 			;
5527c478bd9Sstevel@tonic-gate 		raw();
5538d489c7aSmuffin 		(void) signal(SIGINT, ointr);
5548d489c7aSmuffin 		(void) signal(SIGQUIT, oquit);
5557c478bd9Sstevel@tonic-gate 	} else {
5568d489c7aSmuffin 		int i;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		userperm();
5598d489c7aSmuffin 		(void) dup2(FD, 0);
5608d489c7aSmuffin 		(void) dup2(0, 1);
5617c478bd9Sstevel@tonic-gate 		for (i = 3; i < 20; i++)
5628d489c7aSmuffin 			(void) close(i);
5638d489c7aSmuffin 		(void) signal(SIGINT, SIG_DFL);
5648d489c7aSmuffin 		(void) signal(SIGQUIT, SIG_DFL);
5657c478bd9Sstevel@tonic-gate 		execute(buf);
5668d489c7aSmuffin 		(void) printf("can't find `%s'\r\n", buf);
5677c478bd9Sstevel@tonic-gate 		exit(0);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 	if (boolean(value(VERBOSE)))
5707c478bd9Sstevel@tonic-gate 		prtime("\r\naway for ", time(0)-start);
5718d489c7aSmuffin 	(void) write(fildes[1], (char *)&ccc, 1);
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate /*
5757c478bd9Sstevel@tonic-gate  * Escape to local shell
5767c478bd9Sstevel@tonic-gate  */
5778d489c7aSmuffin /* ARGSUSED */
5788d489c7aSmuffin void
shell(int cc)5798d489c7aSmuffin shell(int cc)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate 	int shpid, status;
5828d489c7aSmuffin 	sig_handler_t	ointr, oquit;
5837c478bd9Sstevel@tonic-gate 	char *cp;
5847c478bd9Sstevel@tonic-gate 
5858d489c7aSmuffin 	(void) printf("[sh]\r\n");
5867c478bd9Sstevel@tonic-gate 	ointr = signal(SIGINT, SIG_IGN);
5877c478bd9Sstevel@tonic-gate 	oquit = signal(SIGQUIT, SIG_IGN);
5887c478bd9Sstevel@tonic-gate 	unraw();
5897c478bd9Sstevel@tonic-gate 	if (shpid = fork()) {
5907c478bd9Sstevel@tonic-gate 		while (shpid != wait(&status))
5917c478bd9Sstevel@tonic-gate 			;
5927c478bd9Sstevel@tonic-gate 		raw();
5938d489c7aSmuffin 		(void) printf("\r\n!\r\n");
5948d489c7aSmuffin 		(void) signal(SIGINT, ointr);
5958d489c7aSmuffin 		(void) signal(SIGQUIT, oquit);
5967c478bd9Sstevel@tonic-gate 	} else {
5977c478bd9Sstevel@tonic-gate 		userperm();
5988d489c7aSmuffin 		(void) signal(SIGQUIT, SIG_DFL);
5998d489c7aSmuffin 		(void) signal(SIGINT, SIG_DFL);
6007c478bd9Sstevel@tonic-gate 		if ((cp = strrchr(value(SHELL), '/')) == NULL)
6017c478bd9Sstevel@tonic-gate 			cp = value(SHELL);
6027c478bd9Sstevel@tonic-gate 		else
6037c478bd9Sstevel@tonic-gate 			cp++;
6048d489c7aSmuffin 		(void) execl(value(SHELL), cp, 0);
6058d489c7aSmuffin 		(void) printf("\r\ncan't execl!\r\n");
6067c478bd9Sstevel@tonic-gate 		exit(1);
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate /*
6117c478bd9Sstevel@tonic-gate  * TIPIN portion of scripting
6127c478bd9Sstevel@tonic-gate  *   initiate the conversation with TIPOUT
6137c478bd9Sstevel@tonic-gate  */
6148d489c7aSmuffin void
setscript(void)6158d489c7aSmuffin setscript(void)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	char c;
61894e1761eSsn 
61994e1761eSsn 	if (strlen(value(RECORD)) >= PATH_MAX-1) {
62094e1761eSsn 		(void) fprintf(stderr, "tip: record file name too long\r\n");
62194e1761eSsn 		return;
62294e1761eSsn 	}
6237c478bd9Sstevel@tonic-gate 	/*
6247c478bd9Sstevel@tonic-gate 	 * enable TIPOUT side for dialogue
6257c478bd9Sstevel@tonic-gate 	 */
6268d489c7aSmuffin 	(void) kill(pid, SIGEMT);
6277c478bd9Sstevel@tonic-gate 	if (boolean(value(SCRIPT)))
6288d489c7aSmuffin 		(void) write(fildes[1], value(RECORD), strlen(value(RECORD)));
6298d489c7aSmuffin 	(void) write(fildes[1], "\n", 1);
6307c478bd9Sstevel@tonic-gate 	/*
6317c478bd9Sstevel@tonic-gate 	 * wait for TIPOUT to finish
6327c478bd9Sstevel@tonic-gate 	 */
6338d489c7aSmuffin 	(void) read(repdes[0], &c, 1);
6347c478bd9Sstevel@tonic-gate 	if (c == 'n')
6358d489c7aSmuffin 		(void) fprintf(stderr, "tip: can't create record file %s\r\n",
6367c478bd9Sstevel@tonic-gate 		    value(RECORD));
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate /*
6407c478bd9Sstevel@tonic-gate  * Change current working directory of
6417c478bd9Sstevel@tonic-gate  *   local portion of tip
6427c478bd9Sstevel@tonic-gate  */
6438d489c7aSmuffin /* ARGSUSED */
6448d489c7aSmuffin void
chdirectory(int cc)6458d489c7aSmuffin chdirectory(int cc)
6467c478bd9Sstevel@tonic-gate {
6477c478bd9Sstevel@tonic-gate 	char dirname[80];
6488d489c7aSmuffin 	char *cp = dirname;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (prompt("[cd] ", dirname, sizeof (dirname))) {
6517c478bd9Sstevel@tonic-gate 		if (stoprompt)
6527c478bd9Sstevel@tonic-gate 			return;
6537c478bd9Sstevel@tonic-gate 		cp = value(HOME);
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 	if (chdir(cp) < 0)
6568d489c7aSmuffin 		(void) printf("%s: bad directory\r\n", cp);
6578d489c7aSmuffin 	(void) printf("!\r\n");
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6608d489c7aSmuffin void
tip_abort(char * msg)6618d489c7aSmuffin tip_abort(char *msg)
6627c478bd9Sstevel@tonic-gate {
6638d489c7aSmuffin 	/* don't want to hear about our child */
6648d489c7aSmuffin 	(void) signal(SIGCHLD, SIG_DFL);
6658d489c7aSmuffin 	(void) kill(pid, SIGTERM);
6667c478bd9Sstevel@tonic-gate 	myperm();
6677c478bd9Sstevel@tonic-gate 	disconnect(msg);
6687c478bd9Sstevel@tonic-gate 	if (msg != NOSTR)
6698d489c7aSmuffin 		(void) printf("\r\n%s", msg);
6708d489c7aSmuffin 	(void) printf("\r\n[EOT]\r\n");
6717c478bd9Sstevel@tonic-gate 	delock(uucplock);
6727c478bd9Sstevel@tonic-gate 	unraw();
6737c478bd9Sstevel@tonic-gate 	exit(0);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6768d489c7aSmuffin /* ARGSUSED */
6778d489c7aSmuffin void
finish(int cc)6788d489c7aSmuffin finish(int cc)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate 	char *dismsg;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if ((dismsg = value(DISCONNECT)) != NOSTR) {
6838d489c7aSmuffin 		(void) write(FD, dismsg, strlen(dismsg));
6848d489c7aSmuffin 		(void) sleep(5);
6857c478bd9Sstevel@tonic-gate 	}
6868d489c7aSmuffin 	tip_abort(NOSTR);
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate void
intcopy(void)6908d489c7aSmuffin intcopy(void)
6917c478bd9Sstevel@tonic-gate {
6927c478bd9Sstevel@tonic-gate 
6938d489c7aSmuffin 	(void) signal(SIGINT, SIG_IGN);
6947c478bd9Sstevel@tonic-gate 	siglongjmp(intbuf, 1);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6978d489c7aSmuffin void
execute(char * s)6988d489c7aSmuffin execute(char *s)
6997c478bd9Sstevel@tonic-gate {
7008d489c7aSmuffin 	char *cp;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(value(SHELL), '/')) == NULL)
7037c478bd9Sstevel@tonic-gate 		cp = value(SHELL);
7047c478bd9Sstevel@tonic-gate 	else
7057c478bd9Sstevel@tonic-gate 		cp++;
7068d489c7aSmuffin 	(void) execl(value(SHELL), cp, "-c", s, 0);
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate 
7098d489c7aSmuffin int
args(char * buf,char * a[],size_t na)7108d489c7aSmuffin args(char *buf, char *a[], size_t na)
7117c478bd9Sstevel@tonic-gate {
7128d489c7aSmuffin 	char *p = buf, *start;
7138d489c7aSmuffin 	char **parg = a;
7148d489c7aSmuffin 	int n = 0;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	do {
7177c478bd9Sstevel@tonic-gate 		while (*p && (*p == ' ' || *p == '\t'))
7187c478bd9Sstevel@tonic-gate 			p++;
7197c478bd9Sstevel@tonic-gate 		start = p;
7207c478bd9Sstevel@tonic-gate 		if (*p)
7217c478bd9Sstevel@tonic-gate 			*parg = p;
7227c478bd9Sstevel@tonic-gate 		while (*p && (*p != ' ' && *p != '\t'))
7237c478bd9Sstevel@tonic-gate 			p++;
7247c478bd9Sstevel@tonic-gate 		if (p != start)
7257c478bd9Sstevel@tonic-gate 			parg++, n++;
7267c478bd9Sstevel@tonic-gate 		if (*p)
7277c478bd9Sstevel@tonic-gate 			*p++ = '\0';
7287c478bd9Sstevel@tonic-gate 	} while (*p && n < na);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	return (n);
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate 
7338d489c7aSmuffin void
prtime(char * s,time_t a)7348d489c7aSmuffin prtime(char *s, time_t a)
7357c478bd9Sstevel@tonic-gate {
7368d489c7aSmuffin 	int i;
7377c478bd9Sstevel@tonic-gate 	int nums[3];
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	for (i = 0; i < 3; i++) {
7407c478bd9Sstevel@tonic-gate 		nums[i] = (int)(a % quant[i]);
7417c478bd9Sstevel@tonic-gate 		a /= quant[i];
7427c478bd9Sstevel@tonic-gate 	}
7438d489c7aSmuffin 	(void) printf("%s", s);
7447c478bd9Sstevel@tonic-gate 	while (--i >= 0)
7457c478bd9Sstevel@tonic-gate 		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
7468d489c7aSmuffin 			(void) printf("%d %s%c ", nums[i], sep[i],
7478d489c7aSmuffin 			    nums[i] == 1 ? '\0' : 's');
7488d489c7aSmuffin 	(void) printf("\r\n!\r\n");
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7518d489c7aSmuffin /* ARGSUSED */
7528d489c7aSmuffin void
variable(int cc)7538d489c7aSmuffin variable(int cc)
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate 	char	buf[256];
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (prompt("[set] ", buf, sizeof (buf)))
7587c478bd9Sstevel@tonic-gate 		return;
7597c478bd9Sstevel@tonic-gate 	vlex(buf);
7607c478bd9Sstevel@tonic-gate 	if (vtable[BEAUTIFY].v_access&CHANGED) {
7617c478bd9Sstevel@tonic-gate 		vtable[BEAUTIFY].v_access &= ~CHANGED;
7628d489c7aSmuffin 		(void) kill(pid, SIGSYS);
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 	if (vtable[SCRIPT].v_access&CHANGED) {
7657c478bd9Sstevel@tonic-gate 		vtable[SCRIPT].v_access &= ~CHANGED;
7667c478bd9Sstevel@tonic-gate 		setscript();
7677c478bd9Sstevel@tonic-gate 		/*
7687c478bd9Sstevel@tonic-gate 		 * So that "set record=blah script" doesn't
7697c478bd9Sstevel@tonic-gate 		 *  cause two transactions to occur.
7707c478bd9Sstevel@tonic-gate 		 */
7717c478bd9Sstevel@tonic-gate 		if (vtable[RECORD].v_access&CHANGED)
7727c478bd9Sstevel@tonic-gate 			vtable[RECORD].v_access &= ~CHANGED;
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 	if (vtable[RECORD].v_access&CHANGED) {
7757c478bd9Sstevel@tonic-gate 		vtable[RECORD].v_access &= ~CHANGED;
7767c478bd9Sstevel@tonic-gate 		if (boolean(value(SCRIPT)))
7777c478bd9Sstevel@tonic-gate 			setscript();
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 	if (vtable[TAND].v_access&CHANGED) {
7807c478bd9Sstevel@tonic-gate 		vtable[TAND].v_access &= ~CHANGED;
7817c478bd9Sstevel@tonic-gate 		if (boolean(value(TAND)))
7827c478bd9Sstevel@tonic-gate 			tandem("on");
7837c478bd9Sstevel@tonic-gate 		else
7847c478bd9Sstevel@tonic-gate 			tandem("off");
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 	if (vtable[LECHO].v_access&CHANGED) {
7877c478bd9Sstevel@tonic-gate 		vtable[LECHO].v_access &= ~CHANGED;
7887c478bd9Sstevel@tonic-gate 		boolean(value(HALFDUPLEX)) = boolean(value(LECHO));
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 	if (vtable[PARITY].v_access&CHANGED) {
7917c478bd9Sstevel@tonic-gate 		vtable[PARITY].v_access &= ~CHANGED;
7927c478bd9Sstevel@tonic-gate 		setparity(NULL);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 	if (vtable[BAUDRATE].v_access&CHANGED) {
7957c478bd9Sstevel@tonic-gate 		vtable[BAUDRATE].v_access &= ~CHANGED;
7967c478bd9Sstevel@tonic-gate 		ttysetup(speed(number(value(BAUDRATE))));
7977c478bd9Sstevel@tonic-gate 	}
7987c478bd9Sstevel@tonic-gate 	if (vtable[HARDWAREFLOW].v_access & CHANGED) {
7997c478bd9Sstevel@tonic-gate 		vtable[HARDWAREFLOW].v_access &= ~CHANGED;
8007c478bd9Sstevel@tonic-gate 		if (boolean(value(HARDWAREFLOW)))
8017c478bd9Sstevel@tonic-gate 			hardwareflow("on");
8027c478bd9Sstevel@tonic-gate 		else
8037c478bd9Sstevel@tonic-gate 			hardwareflow("off");
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate /*
8087c478bd9Sstevel@tonic-gate  * Turn tandem mode on or off for remote tty.
8097c478bd9Sstevel@tonic-gate  */
8108d489c7aSmuffin void
tandem(char * option)8118d489c7aSmuffin tandem(char *option)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	struct termios rmtty;
8147c478bd9Sstevel@tonic-gate 
8158d489c7aSmuffin 	(void) ioctl(FD, TCGETS, (char *)&rmtty);
8167c478bd9Sstevel@tonic-gate 	if (equal(option, "on")) {
8177c478bd9Sstevel@tonic-gate 		rmtty.c_iflag |= IXOFF|IXON;
8187c478bd9Sstevel@tonic-gate 		arg.c_iflag |= IXOFF|IXON;
8197c478bd9Sstevel@tonic-gate 		rmtty.c_cc[VSTART] = defarg.c_cc[VSTART];
8207c478bd9Sstevel@tonic-gate 		rmtty.c_cc[VSTOP] = defarg.c_cc[VSTOP];
8217c478bd9Sstevel@tonic-gate 	} else {
8227c478bd9Sstevel@tonic-gate 		rmtty.c_iflag &= ~(IXOFF|IXON);
8237c478bd9Sstevel@tonic-gate 		arg.c_iflag &= ~(IXOFF|IXON);
8247c478bd9Sstevel@tonic-gate 	}
8258d489c7aSmuffin 	(void) ioctl(FD, TCSETSF, (char *)&rmtty);
8268d489c7aSmuffin 	(void) ioctl(0, TCSETSF, (char *)&arg);
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate /*
8307c478bd9Sstevel@tonic-gate  * Turn hardwareflow mode on or off for remote tty.
8317c478bd9Sstevel@tonic-gate  */
8328d489c7aSmuffin void
hardwareflow(char * option)8338d489c7aSmuffin hardwareflow(char *option)
8347c478bd9Sstevel@tonic-gate {
8357c478bd9Sstevel@tonic-gate 	struct termios rmtty;
8367c478bd9Sstevel@tonic-gate 
8378d489c7aSmuffin 	(void) ioctl(FD, TCGETS, (char *)&rmtty);
8387c478bd9Sstevel@tonic-gate 	if (equal(option, "on")) {
8397c478bd9Sstevel@tonic-gate 		rmtty.c_cflag |= (CRTSCTS|CRTSXOFF);
8407c478bd9Sstevel@tonic-gate 	} else {
8417c478bd9Sstevel@tonic-gate 		rmtty.c_cflag &= ~(CRTSCTS|CRTSXOFF);
8427c478bd9Sstevel@tonic-gate 	}
8438d489c7aSmuffin 	(void) ioctl(FD, TCSETSF, (char *)&rmtty);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate /*
8477c478bd9Sstevel@tonic-gate  * Turn interrupts from local tty on or off.
8487c478bd9Sstevel@tonic-gate  */
8498d489c7aSmuffin void
intr(char * option)8508d489c7aSmuffin intr(char *option)
8517c478bd9Sstevel@tonic-gate {
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	if (equal(option, "on"))
8547c478bd9Sstevel@tonic-gate 		arg.c_lflag |= ISIG;
8557c478bd9Sstevel@tonic-gate 	else
8567c478bd9Sstevel@tonic-gate 		arg.c_lflag &= ~ISIG;
8578d489c7aSmuffin 	(void) ioctl(0, TCSETSF, (char *)&arg);
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate /*
8617c478bd9Sstevel@tonic-gate  * Send a break.
8627c478bd9Sstevel@tonic-gate  */
8638d489c7aSmuffin /* ARGSUSED */
8648d489c7aSmuffin void
genbrk(int cc)8658d489c7aSmuffin genbrk(int cc)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate 
8688d489c7aSmuffin 	(void) ioctl(FD, TCSBRK, 0);
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate /*
8727c478bd9Sstevel@tonic-gate  * Suspend tip
8737c478bd9Sstevel@tonic-gate  */
8748d489c7aSmuffin void
suspend(int c)8758d489c7aSmuffin suspend(int c)
8767c478bd9Sstevel@tonic-gate {
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	unraw();
8798d489c7aSmuffin 	(void) kill(c == _CTRL('y') ? getpid() : 0, SIGTSTP);
8807c478bd9Sstevel@tonic-gate 	raw();
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate  *	expand a file name if it includes shell meta characters
8857c478bd9Sstevel@tonic-gate  */
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate char *
expand(char name[])8888d489c7aSmuffin expand(char name[])
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	static char xname[BUFSIZ];
8917c478bd9Sstevel@tonic-gate 	char cmdbuf[BUFSIZ];
8928d489c7aSmuffin 	int pid, l;
8938d489c7aSmuffin 	char *cp, *Shell;
8947c478bd9Sstevel@tonic-gate 	int s, pivec[2];
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	if (!anyof(name, "~{[*?$`'\"\\"))
8977c478bd9Sstevel@tonic-gate 		return (name);
8987c478bd9Sstevel@tonic-gate 	if (pipe(pivec) < 0) {
8997c478bd9Sstevel@tonic-gate 		perror("pipe");
9007c478bd9Sstevel@tonic-gate 		return (name);
9017c478bd9Sstevel@tonic-gate 	}
9028d489c7aSmuffin 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "echo %s", name);
9037c478bd9Sstevel@tonic-gate 	if ((pid = vfork()) == 0) {
9047c478bd9Sstevel@tonic-gate 		userperm();
9057c478bd9Sstevel@tonic-gate 		Shell = value(SHELL);
9067c478bd9Sstevel@tonic-gate 		if (Shell == NOSTR)
9077c478bd9Sstevel@tonic-gate 			Shell = "/bin/sh";
9088d489c7aSmuffin 		(void) close(pivec[0]);
9098d489c7aSmuffin 		(void) close(1);
9108d489c7aSmuffin 		(void) dup(pivec[1]);
9118d489c7aSmuffin 		(void) close(pivec[1]);
9128d489c7aSmuffin 		(void) close(2);
9138d489c7aSmuffin 		(void) execl(Shell, Shell, "-c", cmdbuf, 0);
9147c478bd9Sstevel@tonic-gate 		_exit(1);
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 	if (pid == -1) {
9177c478bd9Sstevel@tonic-gate 		perror("fork");
9188d489c7aSmuffin 		(void) close(pivec[0]);
9198d489c7aSmuffin 		(void) close(pivec[1]);
9207c478bd9Sstevel@tonic-gate 		return (NOSTR);
9217c478bd9Sstevel@tonic-gate 	}
9228d489c7aSmuffin 	(void) close(pivec[1]);
9237c478bd9Sstevel@tonic-gate 	l = read(pivec[0], xname, BUFSIZ);
9248d489c7aSmuffin 	(void) close(pivec[0]);
9258d489c7aSmuffin 	while (wait(&s) != pid)
9267c478bd9Sstevel@tonic-gate 		;
9277c478bd9Sstevel@tonic-gate 	s &= 0377;
9287c478bd9Sstevel@tonic-gate 	if (s != 0 && s != SIGPIPE) {
9298d489c7aSmuffin 		(void) fprintf(stderr, "\"Echo\" failed\n");
9307c478bd9Sstevel@tonic-gate 		return (NOSTR);
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate 	if (l < 0) {
9337c478bd9Sstevel@tonic-gate 		perror("read");
9347c478bd9Sstevel@tonic-gate 		return (NOSTR);
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 	if (l == 0) {
9378d489c7aSmuffin 		(void) fprintf(stderr, "\"%s\": No match\n", name);
9387c478bd9Sstevel@tonic-gate 		return (NOSTR);
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate 	if (l == BUFSIZ) {
9418d489c7aSmuffin 		(void) fprintf(stderr, "Buffer overflow expanding \"%s\"\n",
9428d489c7aSmuffin 		    name);
9437c478bd9Sstevel@tonic-gate 		return (NOSTR);
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 	xname[l] = 0;
9467c478bd9Sstevel@tonic-gate 	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
9477c478bd9Sstevel@tonic-gate 		;
9487c478bd9Sstevel@tonic-gate 	*++cp = '\0';
9497c478bd9Sstevel@tonic-gate 	return (xname);
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate /*
9537c478bd9Sstevel@tonic-gate  * Are any of the characters in the two strings the same?
9547c478bd9Sstevel@tonic-gate  */
9557c478bd9Sstevel@tonic-gate 
9568d489c7aSmuffin int
anyof(char * s1,char * s2)9578d489c7aSmuffin anyof(char *s1, char *s2)
9587c478bd9Sstevel@tonic-gate {
9598d489c7aSmuffin 	int c;
9607c478bd9Sstevel@tonic-gate 
9618d489c7aSmuffin 	while ((c = *s1++) != 0)
9627c478bd9Sstevel@tonic-gate 		if (any(c, s2))
9637c478bd9Sstevel@tonic-gate 			return (1);
9647c478bd9Sstevel@tonic-gate 	return (0);
9657c478bd9Sstevel@tonic-gate }
966