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();
}