Path: utzoo!mnetor!uunet!husc6!hao!ames!umd5!mimsy!chris
From: chris@mimsy.UUCP (Chris Torek)
Newsgroups: comp.unix.questions
Subject: Re: Another attempt at getting help with process communications
Message-ID: <9801@mimsy.UUCP>
Date: 15 Dec 87 18:53:56 GMT
References: <8214@steinmetz.steinmetz.UUCP>
Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742
Lines: 91

In article <8214@steinmetz.steinmetz.UUCP> lanzo@mercutio.steinmetz
(Mark Lanzo) writes:
[using ptys,]
>The thing which confuses me most is that I don't know how to handle the
>bidirectional communications with a pseudoterminal, especially with the
>master end of the pseudoterminal, which can only be opened once ....

Things written on the master end of a pty pair appear on the slave
end and can be read there.  Things written on the slave end of a
pair appear on the master end, and can be read there.  Things written
on the master end cannot be read back from the master end (unless,
of course, the process on the slave side echoes them).

>... especially if the child process exited so that the slave end of
>the pty wasn't really connected to anything.

When this happens, read(masterfd) should return EOF.

>...I definitely need 2 (or 3) descriptors in the subprocess, since
>these are supposed to be stdin, stdout, and stderr.

	/* assume masterfd is set */
	slavefd = open(slave, 2);
	if (slavefd < 0)
		...	/* something went wrong */
	pid = fork();
	if (pid < 0)
		...	/* something went wrong */
	if (pid == 0) {
		/* child */
		if (dup2(slavefd, 0) < 0 || dup2(0, 1) < 0 || dup2(0, 2) < 0)
			...
		/* discard irrelevent descriptors */
		for (i = getdtablesize(); --i > 2;)
			(void) close(i);
		exec...
		/* get here iff exec fails, so send message to master */
		perror("exec(...)");
		_exit(1);
	}
	(void) close(slavefd);	/* do not want this anymore */
	/* go on with master stuff */

>    How do I locate an unused pty/tty pair;

There should be a nice way to do this, but all existing programs loop
trying to open ptyp0, then ptyp1, then ptyp2, ... ptypf, ptyq0, ....

>and how do I ensure that nothing else tries to access the pty while
>my job is using it?

As long as you have the master end open, no one else can touch it.
Of course, anyone with the proper permissions can open the slave end.

>What if there is NO currently unused pty?

Then you are out of luck.  `Good' programs currently use stat() to
tell whether there is a block of ptys:

	(void) strcpy(name, "/dev/ptyXX");
	for (c = 'p'; c <= 'z'; c++) {
		name[sizeof("/dev/pty") - 1] = c;
		if (stat(name, &st))
			break;	/* no ptys */
		for (i = 0; i < 16; i++) {
			name[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
			if ((masterfd = open(name, 2)) >= 0)
				goto havemaster;
		}
	}
	/* no ptys */
	...
havemaster:
	/* have the master end */

Note that some wayward programs sometimes leave slave pty protections
such that even after someone opens the master, that user cannot open
the slave.  (Root need not worry about this, of course.)  Hence it
is a safer to do something like this:

			if ((masterfd = open(name, 2)) < 0)
				continue;
			name[sizeof("/dev/p") - 1] = 't';
			if ((slavefd = open(name, 2)) >= 0)
				goto havepty;
			/* someone left a pty unusable; just move on */
			(void) close(masterfd);

-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris