getcwd() and friends.

Kenneth Almquist ka at june.cs.washington.edu
Sun Apr 16 08:26:22 AEST 1989


peter at ficc.uu.net (Peter da Silva) writes:
> [Suggestion for O_TOKEN.]
>
> Do this cleverly enough and almost all the regular calls can actually use
> the new calls... you just need to keep 'open' around so you can get the
> fd in the first place:
> 
> 	link(name, newname)
> 	char *name, *newname;
> 	{
> 		int fd;
> 
> 		fd = open(name, O_TOKEN);
> 		if(fd >= 0)
> 		{
> 			retval = fd_link(fd, newname);
> 			close(fd);
> 		}
> 		else
> 			return -1;
> 	}

A good idea in principle, but the code you present here contains three
rather obscure bugs which are worth pointing out in case someone decides
to implement this.

First, the open can fail because of a lack of open file descriptors, and
EMFILE isn't one of the error codes that link is supposed to return.

Second, there is no guarantee that the open system call will ever return;
for example an open of a tty device blocks until carrier is present, and
it may never be.

Third, if a signal arrives between the open and the close, and the signal
handler does a longjmp out of the link routine, the file descriptor will
never be closed.  

The second problem is easily fixed by adding the O_NDELAY flag to the open
call.  The other two are harder.  The third can be solved by blocking all
signals before the open, and unblocking them after the close.  The main
problem with this is that, with a networked file system, you may want link
to be interruptable.  The first problem can be fixed by reserving the last
file descriptor for routines like link.  To do this, make the system calls
refuse to allocate the last file descriptor under ordinary circumstances.
Then allow the open call to allocate the last file descriptor if the
O_USELAST flag is set.  By convention, user code should not use O_USELAST.
Putting this all together gives:

	link(name, newname)
	char *name, *newname;
	{
		int fd;
		int savemask;

		savemask = sigblock(~0);	/* block all signals */
		fd = open(name, O_TOKEN|O_NDELAY|O_USELAST);
		if(fd >= 0)
		{
			retval = fd_link(fd, newname);
			close(fd);
			sigblock(savemask);	/* unblock signals */
			return 0;
		}
		else {
			sigblock(savemask);
			return -1;
		}
	}

Kenneth Almquist



More information about the Comp.unix.wizards mailing list