[mod.computers.masscomp] using masscomp ptys

Stan@soma.UUCP (06/26/86)

Enclosed is a recent article in unix-wizards about ptys.
I can't get it to work on RTU. Can anyone tell me why?
Stan
----------------------------------------------------------------
These are the hacks I used to play with ptys on rocksvax.  Even a
"stty cbreak" is undependable.  This code is in a state of change
but is sufficient to show the undependable raw psuedo-ttys.


//Z\\
James M. Ziobro
Ziobro.Henr@Xerox.COM
{rochester,amd,sunybcs,ihnp4}!rocksvax!z
Ziobro:henr801g:xerox

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	ourcom
#	ptytest.c
# This archive created: Tue Jun 17 16:04:17 1986
cat << \SHAR_EOF > README
Create a file "feedem" of about 16000 characters.  The "cmp" feedem and dd.CKP
after running the program.  You will notice random characters are dropped.

Removing the "stty raw" from ourcom allows for a "good" transmission of
a file without special characters.

To use:
1.) Make sure "ourcom" is execuatable.
2.) Make sure "feedem" is at least 16k long.
3.) The ptytest program is invoked with the count of characters to be written
	with each write.
	(e.g. ptytest 10)
SHAR_EOF
cat << \SHAR_EOF > ourcom
#!/bin/sh
stty all 2> stty1.CKP
stty raw -echo 110
# stty  new cbreak
stty all 2> stty2.CKP
exec dd of=dd.CKP bs=1 count=15719
SHAR_EOF
chmod +x ourcom
cat << \SHAR_EOF > ptytest.c
#ifndef lint
static char rcsid[] = "$Revision: 1.1 $";
#endif

#include <stdio.h>
#include <sgtty.h>
#include <sys/file.h>
#include <sys/signal.h>

#define DEBUG(a,b) fprintf(stderr,a,b)
#define FidMask(f)	(1<<(f))
int forkid;

int ptyopn()
/* return either (-1) or fd */
{
	int fd;
	register char *cp;
	int i;
	char ttbuf[12]; /* /dev/ttypx */
	char bufk[8]; /* tmp buffer */

	for ( i=0xf ; i>=0 ; i-- ) {
		sprintf(ttbuf, "/dev/ptyp%1x", i);
		DEBUG( "opening %s\n", ttbuf);
		fd = open(ttbuf, O_RDWR);
		if ( fd >= 0 ) {
			sprintf(ttbuf, "/dev/ttyp%1x", i);
			i= -1;
			};
		};
	if (fd < 0) {
		return(-1);
	}
	DEBUG("fd - %d\n", fd);

	if((forkid=fork())==0) {
		close(0);
		close(1);
		if(open(ttbuf,O_RDONLY)!=0) {
		    exit(-1);
		    };
		if(open(ttbuf,O_WRONLY)!=1){
		    exit(-1);
		    };
		/* No debug stmts here because they would confuse the parent */
		execl("./ourcom", "OURCOM", 0);
	};
	DEBUG("execl ourcom %d\n", forkid);
	sprintf(bufk,"%d", forkid);
	return(fd);
}
ptycls(fd)
int fd;
{
long int waitcnt;

	char bufk[8]; /* tmp buffer */
	DEBUG("PTY CLOSE called\n", 0);
	if (fd > 0) {
		int ret;
		union wait *stat;

		/* ioctl(fd, FIONREAD, &waitcnt);

		if(waitcnt>0) while ( read(fd, bufk, 7) > 0) {
			DEBUG("i-dequeue:'%s'\n", bufk);
			};
			*/
		DEBUG("kill child %d\n", forkid);
		ret = kill(forkid, SIGKILL);
		DEBUG("kill ret %d\n", ret);
		sprintf(bufk,"%d", forkid);
		/* ret = wait(0); ??????????????????? */
		ret = fcntl(fd, F_GETFL, 0);
		DEBUG("GETFL ret 0x%x\n", ret);
		ret = fcntl(fd, F_SETFL, ret|FNDELAY);
		DEBUG("SETFL ret %d\n", ret);

		while ( read(fd, bufk, 7) > 0) {
			DEBUG("dequeue:'%s'\n", bufk);
			};
		DEBUG("close fd %d\n", fd);
		ret = close(fd);
		DEBUG("close ret %d\n", ret);
	}
}

int ptyFd; /* our control pty file descriptor */

timeout(){
	DEBUG("We timed out - %d", ptyFd);
	ptycls(ptyFd);
	exit(1);
};

#define BUFLEN 20000
main(argc,argv)
int argc;
char *argv[];
{
int inJunk; /* Junk to sendthem */
int cnt; /* count of Junk */
char buf[BUFLEN+512];
int wcnt;
struct sgttyb tbuf;
int i;
int totalWritten=0;

if(argc>1) {
	wcnt=atoi(argv[1]);
	};

if (wcnt<=0)wcnt=1;
DEBUG("wcnt = %d\n", wcnt);

ptyFd = ptyopn();
if (ptyFd<0) {
	DEBUG("ptyopn FAILED %d", ptyFd);
	exit(1);
	};
sleep(5);
i=ioctl(ptyFd, TIOCGETP, tbuf);
DEBUG("flags=%x\n", tbuf.sg_flags);

/* sprintf(buf, "stty raw\n"); write(ptyFd, buf, strlen(buf)); */
/* sprintf(buf, "cmp - feedem > cmpout.CKP\n"); write(ptyFd, buf, strlen(buf)); */

inJunk=open("feedem", O_RDONLY);

if (inJunk<0) {
	ptycls(ptyFd);
	exit(1);
	};

nice (14);
signal(SIGALRM, timeout);
while( (cnt=read(inJunk, buf, BUFLEN)) > 0 ) {
	int ocnt;
	int tcnt;
	int i;
	int infd,outfd;
	int n;


#define W wcnt
#define MIN(x,y)	((x)<(y)?x:y)
	for (tcnt=0; tcnt<cnt; tcnt=tcnt+ocnt) {
	    signal(SIGALRM, timeout);
	    alarm(120); ocnt = write(ptyFd, buf+tcnt, MIN(W,cnt-tcnt) ); 
	    DEBUG("wrote %d bytes", ocnt);
	    totalWritten = totalWritten + ocnt;
	    if(ocnt<0) {
		perror("pty write failed");
		DEBUG("wrote %d bytes", tcnt);
		ptycls(ptyFd);
		exit(1);
		};
#ifndef NOSELECT
	    infd=outfd=FidMask(ptyFd);
	    n=select(4,&infd,&outfd,0,0);
	    if(outfd==0){
		perror("select passed on");
		ptycls(ptyFd);
		exit(1);
		};
#endif NOSELECT
	    alarm(0);
	    };
/*	alarm(30); ocnt = write(ptyFd, buf, cnt);
	alarm(0);
	DEBUG("wrote %d", ocnt); */
	};
DEBUG("wrote %d\n", totalWritten); 
alarm(30);wait(0);
ptycls(ptyFd);

};
SHAR_EOF
#	End of shell archive
exit 0

Jeff@soma.UUCP (07/02/86)

The program has 2 major problems: It opens the wrong device, and it
never reads from the master pseudo-tty. The string '/dev/ptyp%1x' in
ptyopen should be replaced with '/dev/pty%1x', otherwise the open always
fails. After this is done, the program execs the script properly,
which then blocks on the second stty command. The problem is that 
the stty command produces output, which is not redirected, so it is
written to the tty (pseudo-tty). There is a 256 character buffer
for each tty device, and when this fills, the write blocks. There 
are 2 solutions: read (or flush) from the master side, or simply redirect
the output of the stty commands. Included is a version of 'ourcom'
that works. By works, I mean that the file dd.CKP shows up and is not
scrambled. I'm not sure what is wrong with the original poster's system,
but his program seems to work as intended. For those of you that have
access to UNIX sources, the 'script' program gives a much better
(read: faster) way to search for available pty's, and a cleaner
manipulation of them afterwards.

#!/bin/sh
stty all > stty1.CKP 2>&1
stty raw -echo 110
# stty  new cbreak
stty all > stty2.CKP 2>&1
exec dd of=dd.CKP bs=1 count=15719


[Thanks for the information! - sob]