fcntl() versus ioctl()

Guy Harris guy at gorodish.Sun.COM
Fri Sep 16 04:33:29 AEST 1988


> Well, this is a good question.  Let's examine it.  First of all, note
> that fcntl(2) operates on file descriptors (just like ioctl(2) does).

Well, no.  "fcntl()" and "ioctl()" both take file descriptors as arguments.
However, they don't necessarily "operate on" those descriptors, in the sense
that they may fetch information from, or change the state of, objects to which
those descriptors refer, rather than the descriptors themselves.

"fcntl()" acts either on the file descriptor or on the file table
entry to which the descriptor refers (later UNIX releases also added other
functions, such as record locking, which don't fit this model, but you can
argue that they should have added a new call for those; 4.2BSD also
misimplemented no-delay mode as an "ioctl()", and had the "fcntl()" basically
do the "ioctl()" for you, but the original implementation of "fcntl()" in S3
got this right).

"ioctl()" generally acts on the object (file, device) to which the file table
entry referred to by the file descriptor refers (earlier UNIX releases stuck
functions such as FIOCLEX that operate on the descriptor and leave everything
below it alone, but you can argue that adding "fcntl()" for this function was
the right idea).

> In many environments, it even offers several of the same sorts of
> controls.

The only such control I can think of is FIOCLEX, and you can argue that, in a
pure sense, this shouldn't have been an "ioctl()" but should only have been an
"fcntl()".

> I don't see any moral difference between fcntl(2) and ioctl(2), myself.

See above.

> Thus, if ioctl() might cause a parent to suffer, fcntl() may be expected
> to have a similar hazard.

In general, both "fcntl()" and "ioctl()" *can* act on objects that are shared
by various file descriptors, so they *might* cause objects shared with a parent
to be affected.

However, while (with the exception of FIOCLEX, which could be argued shouldn't
have been an "ioctl()") "ioctl()" acts *only* on shared objects, "fcntl()"
*can* act on non-shared objects (the file descriptor itself).

Given that, the no-delay flag could have been a flag associated with the file
descriptor entry, in which case the parent will *not* be affected if a process
sets no-delay mode.

The argument you gave indicates that it is certainly *possible* for "fcntl()"s
setting no-delay mode to affect descriptors in the parent, but it basically
amounts to "this is how it was implemented"; it certainly was implemented that
way, but it didn't necessarily *have* to be implemented that way.  It could
conceivably have been implemented as a per-descriptor flag (similar to the
"close-on-exec" flag).

> Now, consider the effect proposed by maart at cs.vu.nl above: that the
> parent's fd should not be affected by a child's action.  Mainly, the
> "stty" command (remember: commands are run as children of shells) no
> longer works.  It is no longer practical to change your tty modes.

Well, no.  He specifically referred to "fcntl()"s done by the child, not
"ioctl()"s done by the child; there already exists a precedent for "fcntl()"s
that don't affect the parent (F_SETFD), and in fact there even exists a
precedent for "ioctl()"s that don't affect the parent (FIOCLEX).

Implementing no-delay mode as a per-descriptor flag would hardly imply that
"ioctl()"s such as the terminal "ioctl()"s would be obliged not to affect
parents of the process doing the "ioctl()".



More information about the Comp.unix.questions mailing list