PEX(4)

NAME
pex - ioctl requests for process-exclusive access

SYNOPSIS
#include <sys/pex.h>

ioctl(fildes, FIOPX, p)
struct pexclude *p;

ioctl(fildes, FIONPX, p)
struct pexclude *p;

ioctl(fildes, FIOQX, p)
struct pexclude *p;

ioctl(fildes, FIOAPX, p)
struct pexclude *p;

ioctl(fildes, FIOANPX, p)
struct pexclude *p;

DESCRIPTION
These ioctl(2) requests provide and check temporary exclusive access to an input/output source. FIOPX marks as `pexed' the file or pipe end referred to by fildes. On a pexed file read, write(2), and most forms of ioctl work only in the pexing process. Moreover, these operations do not work in any process on a half-pexed pipe (a pipe with exactly one pexed end). The mark remains until the pexing process requests FIONPX or closes all file descriptors that refer to the file.

When fildes refers to a stream, FIOPX and FIONPX require the stream's input and output queues to be empty; pex(3) gives a method for emptying them. When fildes refers to a pipe, the far end of which is unpexed, FIOPX waits, with timeout, for an answering FIOPX or FIONPX at the far end. FIONPX waits similarly when the far end is pexed. Either request returns 1 when it leaves a pipe with exactly one end pexed. A pipe must cycle through the fully unpexed state between fully pexed states; from the time one end becomes unpexed until the far end does too, FIOPX on the unpexed end will return error ECONC.

If argument p is nonzero, the structure it points to is filled in with information about the pexedness of the file and about the process at the far end of a pexed pipe. The format, defined in <sys/filio.h> is:
    struct pexclude {
    	int oldnear;	/* FIOPX or FIONPX: state at beginning of call */
    	int newnear;	/* FIOPX or FIONPX: state at end of call */
    	int farpid;	/* -1 if not pipe, 0 if not pexed, else process id */
    	int farcap;	/* if farpid>0, capabilities */
    	int faruid;	/* if farpid>0, user id */
    };
Capabilities are represented as in the lb_t field of a label; see getflab(2).

FIOQX obtains the information without affecting state.

Read, write, or ioctl calls that fail due to pexedness return error ECONC. The only ioctl requests that may succeed on a half-pexed pipe are FIOCLEX, FIONCLEX, FIOPX, FIONPX, and FIOQX. A half-pexed pipe is deemed ready by select(2).

FIOANPX and FIOAPX modify the response of open stream device files to FIOPX requests. They require T_EXTERN capability; see getplab(2). After FIOANPX all FIOPX requests on the special file return 1 and leave the device in an unusable state (as if the device driver were a process at the far end of a pipe, always responding FIONPX). The treatment is reversed with FIOAPX. This mechanism allows a terminal to be denounced to the kernel as being attached to an untrusted remote computer that cannot guarantee the exclusivity asked by FIOPX.

EXAMPLES
A program collecting a password wishes to exclude other programs from the dialogue. The following code does the trick. (When the dialogue passes through mux(9.1) or con(1), downstream stages of the path to the terminal can be assumed to be similarly pexed, provided FIOPX succeeds.)

        #define ok(p) (p->farpid==-1 || p->farpid>0 && p->farcap!=0)
        struct pexclude x;
        if(ioctl(fd, FIOPX, &x) == 0 && ok(&x)) {
        	static char buf[9];
        	write(fd, promptstr, strlen(promptstr));
        	read(fd, buf, 8);
        	s = buf;
        } else
        	s = 0;
        ioctl(fd, x.oldnear, 0);	/* restore state */

An intervening trusted program, with a policy of recognizing exclusive access only for trusted processes, may cooperate with

        n = read(fd, buf, BUFSIZE);
        if(n == -1 && errno == ECONC) {
        	if(ioctl(fd, FIOPX, &pexcode)!=0 || pexcode.farcap==0)
        		ioctl(fd, FIONPX, 0);
        	} else  /* improper pexing */

SEE ALSO
ioctl(2), pipe(2), stream(4), pex(3)

DIAGNOSTICS
EBADF, ECONC, EFAULT, EIO, ENOTTY (FIOAPX and FIOANPX)
ECONC for forbidden IO calls in other processes.
EBUSY for an undrained queue.