kloo@csws13.ic.sunysb.edu (Kwok L Loo) (12/19/90)
I am working on a program using pty/tty pseudo terminal driver. I have read some similar programs implemented on SUN. However, my program will be run on HP 7.0 and many functions are different from those on SUN. When I try to run my program, it does not work properly, if anyone can give me suggestions, or even examples will be greatly appreciated. The program is that I need to open a pseudo terminal and fork a process, which the child process will invoked 'execv' system call to apply a system function, e,g, csh, or jove. Then the communication will be connected through the pseudo terminal. There is some concept and functions I do not understand. It seems like I need to get the controlling terminal to the calling process, then my program will be able to do I/O. Could anyone tell me the concept of controlling terminal and how to get a controlling terminal to a process? also I need to know about process group id and terminal id, since they are useful to get a controlling terminal. Beside, I need to use a CBREAK mode to read data in blocks size. The following is one of my testing program implmented on mailx. I am looking forward to answering. p.s. (NO BSD UNIX & SUN functions) /*** Use PTY ***/ #include <stdio.h> #include <string.h> #include <sgtty.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/file.h> #include <sys/ioctl.h> #define NEWSIZE 20 int master_tty_id; /* parent process, master tty id */ FILE *master_fp = NULL; /* file pointer of master tty */ int fork_pid; /* process id thru fork system call */ static char *pty = "/dev/pty??"; /* master side of pseudo-terminal */ static char *tty = "/dev/tty??"; /* slave side of pseudo-terminal */ static int openMaster() { int i, master; char c; for (c='p'; c<='s'; c++) { pty[8] = c; for (i=0; i<16; i++) { pty[9] = "0123456789abcdef"[i]; if ((master = open(pty, O_RDWR)) != -1) return (master); } } fprintf(stderr, "xmail: all ptys in use\n"); exit(1); } /* openMaster */ static int openSlave() { int slave; tty[8] = pty[8]; tty[9] = pty[9]; if ((slave = open(tty, O_RDWR)) != -1) { return (slave); } else { fprintf(stderr, "open: cannot open slave pty %s", tty); exit(1); } } /* openSlave */ /****************************************************************/ /* */ /* function for implementing mailx */ /* */ /****************************************************************/ int check_for_mail() { char *mbox; struct stat buf; if ((mbox = (char *) getenv("MAIL")) == NULL) { fprintf(stderr, "Mailbox not found!. Please set $MAIL"); return 1; } if (stat(mbox, &buf) == -1) { fprintf(stderr, "No mail for %s\n",getlogin()); return 1; } return 0; } void app_pty(argc, argv) int argc; char *argv[]; { struct sgttyb Sgtty; int pid, pgrp; int fd; int master; /* file descriptor of master pty */ int slave; /* file descriptor to slave pty */ char buf[NEWSIZE], ch; int size, remaining; /* open pty, tty */ master = openMaster(); slave = openSlave(); fork_pid = fork(); if (fork_pid == -1) { /* fork fail */ fprintf(stderr,"Cannot fork mail process"); exit(1); } else if (fork_pid) { /* * Parent : ->close the slave side of pty, * ->close stdin and stdout, * ->set the file descriptor to nonblocking mode, * ->open file pointer with read/write access to child process, * ->set unbuffered mode. */ close(slave); if (master != 0) /* if we're restarting, master is 0 */ close(0); close(1); /* set nonblocking mode */ fcntl(master, F_SETFL, O_NDELAY); master_tty_id = master; /* use descriptor for reads */ master_fp = fdopen(master, "r+"); /* need master_fp for fputs */ setvbuf(master_fp, buf, _IOFBF, NEWSIZE); for (;;) { while ((size = read(master_tty_id, buf, NEWSIZE)) == -1); if (size != 0) { buf[size] = '\0'; write(2, buf, strlen(buf)); write(1, "1\n", 2); ioctl(master_tty_id, FIONREAD, &remaining); } write(0, "h\n", 2); write(1, "h\n", 2); } } else { /* * Child : ->close master side of pty, * ->redirect stdin, stdout, stderr of child process to pty, * ->unbuffer output data from child process, * ->exec sytem called with arguments. */ close(master); ioctl(slave, TIOCGETP, &Sgtty); Sgtty.sg_flags &= ~(ECHO|CRMOD); /* no echo, no NL to CR */ ioctl(slave, TIOCSETP, &Sgtty); /* redirect stdin, stdout, stderr */ dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); if (slave > 2) close(slave); fcntl(1, F_SETFL, FAPPEND); setbuf(stdout, NULL); tcgetpgrp(0, &pgrp); setpgrp(0, pgrp); pid = getpid(); tcsetpgrp(0, pid); setpgrp(0, pid); execl("/usr/bin/mailx", "mailx", (char *) 0); exit(1); } } /* app_pty */ main() { if (check_for_mail() == 0) app_pty(); }