when is the arg for F_GETFL fcntl command required?

房东的猫 提交于 2019-12-10 17:13:46

问题


int fcntl(int fd, int command, ... /* arg */ );

Is it portable: flags = fcntl(fd, F_GETFL); (note: no arg)?

Both Linux and FreeBSD man pages say that arg is ignored:

F_GETFL (void)
    Get the file access mode and the file status flags; arg
    is ignored.

void in Linux documentation means that arg is not required.

Here's a usage example from POSIX for a related F_GETFD flag:

#include <unistd.h>
#include <fcntl.h>
...
    int flags;


    flags = fcntl(fd, F_GETFD);
    if (flags == -1)
        /* Handle error */;
    flags |= FD_CLOEXEC;
    if (fcntl(fd, F_SETFD, flags) == -1)
        /* Handle error */;"

It shows that arg is not required for F_GETFD (today). Then it says:

The arg values to F_GETFD, F_SETFD, F_GETFL, and F_SETFL all represent flag values to allow for future growth.

Does it imply that F_GETFL might use arg in the future?

A quick search for "F_GETFL" on Ohloh code creates an impression that most open-source projects do pass arg(usually 0, sometimes NULL, or even (broken?) &fl). I don't understand why fcntl(fd, F_GETFL, 0) is the preferred form. @Wumpus Q. Wumbley suggests that it might be caused by "Advanced Programming in the UNIX Environment" book that also uses fcntl(fd, F_GETFL, 0) form.

Is there a system/compiler that requires the 3rd arg: flags = fcntl(fd, F_GETFL, 0);? Can fcntl(fd, F_GETFL) and fcntl(fd, F_GETFL, 0) produce different results today or in the future (assuming a compliant implementation)?


回答1:


Look at the rest of the fcntl commands. Notice how some of them (F_DUPFD, F_SETFL, and others) tell you what the third arg is used for. You need to provide the third arg when using one of those. Not when using F_GETFL or F_GETFD.

In the SYNOPSIS you can see that the fcntl takes 2 args plus a ... which means the third arg can be omitted when it's not going to be used.

After doing some more research, I found that there are some old man pages (from around the time of the first APUE) in which the SYNOPSIS implies that all 3 arguments are required. Example: http://www.freebsd.org/cgi/man.cgi?query=fcntl&manpath=FreeBSD+2.2.7-RELEASE

SYNOPSIS
     #include <fcntl.h>

     int
     fcntl(int fd, int cmd, int arg);

I can't find any evidence that it was ever actually declared that way in the header, but if it was, then compilation would fail when it was called with only 2 arguments. That would be a good reason to include the extra 0 argument in your code.

If my guess is correct and this is the actual reason for the historical use of 3-arg F_GETFL then it is a useless fossil from a time when function prototypes were new and scary and OS vendors were getting them wrong.




回答2:


In the FreeBSD base system, both fcntl(fd, F_GETFL) and fcntl(fd, F_GETFL, 0) are used. But in most cases the third argument 0 is used. This could be for historical reasons since fcntl dates back to 4.2BSD, and was imported into FreeBSD via the 4.4BSD-Lite source code.

In 4.4BSD (and FreeBSD 2.0), the manual page listed the argument as mandatory: int fcntl(int fd, int cmd, int arg), even though the actual old-school header does not: int fcntl(int, int, ...).

As to the why, that will be difficult to answer. We'd have to ask the original author(s). But since there are no (user)names recorded in the original source control tags I wouldn't know how to trace them.

The extra 0 argument was probably never removed in the FreeBSD codebase because it doesn't break anything and so isn't important enough to "fix".




回答3:


These two calls

flags = fcntl(fd, F_GETFL);
flags = fcntl(fd, F_GETFL, 0);

are equivalent because the third variadic parameter is ignored. If you take a look at fs/fcntl.c:262 and fs/fcntl.c:269 you will see that arg is not used.
However, when you need to set some value, you should pass the value you want to set.
You could consider fcntl as the OOP equivalent of the getters and setters.

Is there a system that requires the 3rd arg: flags = fcntl(fd, F_GETFL, 0);?

I am not aware of any. Linux doesn't, at least. The documentation clearly states that it's ignored as there would be no use of arg. The fact that you can pass something does not imply you have to.

Can fcntl(fd, F_GETFL) and fcntl(fd, F_GETFL, 0) return different result on some system (in the past, today, and in the future (assuming the conforming implementation))?

lxr allows us to dig into older versions of Linux and even in the 1991, with Linux 2.0.4, fcntl passed over the third argument. There is no meaning to accept any further argument. Therefore, if there's a system where that third argument has a meaning, it isn't Linux for sure.


I've made some further research and I've found some conflicting results. Look at here: there are some books (I don't post a direct link to them as they might be protected) which do propose fcntl as a three arguments function. But, at least regarding GETFL/GETFD, no mention is done about arg.
IMHO, its behavior has never been taken seriously: that is, what makes you wonder. Furthermore, I would even consider it harmful to use that third argument: what if it does/will have a meaning?

I've gone through Linux again, and the third argument for those commands is never passed.

Finally

Is there a system/compiler that requires the 3rd arg: flags = fcntl(fd, F_GETFL, 0);? Can fcntl(fd, F_GETFL) and fcntl(fd, F_GETFL, 0) produce different results today or in the future (assuming a compliant implementation)?

The future is mystery. Today I feel enough sure to exclude that. However, in the past it might have been so.



来源:https://stackoverflow.com/questions/25061656/when-is-the-arg-for-f-getfl-fcntl-command-required

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!