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]