您的位置:首页 > 运维架构 > Linux

fcntl Linux

2016-02-09 16:47 609 查看
fcntl
用于改变已经打开的文件属性

原型如下:

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );
//Returns: depends on cmd if OK(看接下来的内容),-1 on error


在本章节的例子中,第三个参数总是整数。在14.3的文件锁,第三个参数就成为了结构指针。

fcntl
有五种用途:
1.复制已经存在的描述符(cmd = F_DUPFD)
2.Get/Set file descriptor flags(文件描述符标志)(cmd = F_GETFD or F_SETFD)
3.Get/Set file status flags(文件状态标志)(cmd = F_GETFL or F_SETFL)
4.Get/Set asynchronous(异步) I/O ownership(拥有权)(cmd = F_GETOWN or F_SETOWN)
5.Get/Set record locks(记录锁)(cmd = F_GETLK, F_SETLK, or F_SETLKW)

Duplicating a file descriptor

F_DUPFD (int)

Find the lowest numbered available file descriptor greater than or equal to arg and make it be a copy of fd. This is different from dup2(2), which uses exactly the descriptor specified. On success, the new descriptor is returned. See dup(2) for further details.

新的描述符有其自己的文件描述符集,此外它的
FD_CLOEXEC
文件描述符标志被清除(这意味着通过
exec
该描述符保持打开,具体内容在第八章讨论)

F_DUPFD_CLOEXEC (int; since Linux 2.6.24)

As for F_DUPFD, but additionally set the close-on-exec flag for the duplicate descriptor. Specifying this flag permits a program to avoid an additional fcntl() F_SETFD operation to set the FD_CLOEXEC flag. For an explanation of why this flag is useful, see the description of O_CLOEXEC in open(2).

File descriptor flags

The following commands manipulate the flags associated with a file descriptor. Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. If the FD_CLOEXEC bit is 0, the file descriptor will remain open across an execve(2), otherwise it will be closed.

F_GETFD (void)

Read the file descriptor flags; arg is ignored.

F_SETFD (int)

Set the file descriptor flags to the value specified by arg.

In multithreaded programs, using fcntl() F_SETFD to set the close-on-exec flag at the same time as another thread performs a fork(2) plus execve(2) is vulnerable to(伤害) a race condition that may unintentionally leak the file descriptor to the program executed in the child process. See the discussion of the O_CLOEXEC flag in open(2) for details and a remedy to the problem.

File status flags

Each open file description has certain associated status flags, initialized by open(2) and possibly modified by fcntl(). Duplicated file descriptors (made with dup(2), fcntl(F_DUPFD), fork(2), etc.) refer to the same open file description, and thus share the same file status flags.The file status flags and their semantics(语义学)are described in open(2).

F_GETFL (void)

Get the file access mode and the file status flags; arg is ignored.

F_SETFL (int)

Set the file status flags to the value specified by arg. File access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored.On Linux this command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags. It is not possible to change the O_DSYNC and O_SYNC flags; see BUGS, below.

Managing signals

F_GETOWN, F_SETOWN, F_GETOWN_EX, F_SETOWN_EX, F_GETSIG and F_SETSIG are used to manage I/O availability signals:

F_GETOWN (void)

Get the process ID or process group ID currently receiving the SIGIO and SIGCURG signals. We describe these asynchronous I/O signals in Section 14.6.2

F_SETOWN

Set the process ID or process group ID to receive the SIGIO and SIGCURG signals. A positive arg specifies a process ID. A negative arg implies a process group ID equal to the absolute value of arg

Return

fcntl的返回值取决于命令。所有的指令遇到错误时返回-1,成功时返回一些其他数值。下列4个命令具有特殊的返回值:F_DUPFD, F_GETFD,F_GETFL,_F_GETOWN

第一个返回新的文件描述符,接下来两个返回相应的flags,最后一个返回正的process ID或者负的process group ID。

Example1

本例用于显示指定fd所指文件的属性

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
int val;
if(argc != 2)  //必须是两个参数
{
fprintf(stderr, "usage: a.out <descriptor#>");
exit(-1);
}
if((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)//取出file status flags
{
fprintf(stderr, "fcntl error for fd:%d %s", atoi(argv[1]), strerror(errno));
exit(-1);
}

switch(val & O_ACCMODE){    //O_ACCMODE取出文件的读写权限
case O_RDONLY:
printf("read only");
break;
case O_WRONLY:
printf("write only");
break;
case O_RDWR:
printf("read write");
break;
defalut:
printf("unkonw access mode");
exit(-1);
}
if(val & O_APPEND)   //测试其他属性
{
printf(", apppend");
}
if(val & O_NONBLOCK)
{
printf(", nonblocking");
}
putchar('\n');

return 0;
}


编译后在终端测试:

$./a.out 0 < /dev/tty
read only


/dev/tty 是什么呢?

tty是Teletype,这个文件顾名思义,主要用来表示用户的终端,但是它跟普通的终端又有差异。普通的终端是指一些硬件设备,如显示器等等。通常情况下,标准输出或者标准错误流的文件都会输出到终端中。但是,这些标准的输入输出往往不能够输入到/dev/tty文件中。而是需要通过重定向功能,把一些命令的输出重定向到这个文件中。另外需要说明的是,普通终端的话往往是每个用户之间相互独立的。也就是说,每个用户的输出彼此之间是互不干涉的。在用户A的终端中不能够看到用户B的终端信息。但是/det/tty这个文件由其特殊性。这个终端文件可以由各个用户共享。正是因为这个文件有这方面的特殊性,为此在实际工作中系统工程师经常需要用到这个文件。

此外/dev/tty在Unix有一些妙用,详细内容链接:http://www.educity.cn/net/513565.html

./a.out 1 > temp.foo
write only
./a.out 2 2>>temp.foo
write only, append


>是重定向到文件中,会覆盖原有内容,另一个功能是创建新文件,类似于
touch
功能

>>也是重定向,但功能是尾部追加内容

./a.out 5 5<>temp.foo
read write


5<>temp.foo意思是 文件temp.foo用于文件描述符5的读和写。

Example2

本例用于改变指定fd所指文件的属性或者文件状态标志(file descriptor flags or file status flags)

方法就是先获得文件原有的标志值(flag value),然后改变其中需要改变的部分,最后将新值(new flag value)保存回去。

* 我们不能简单使用F_SETFD or F_SETFL,这样会清除掉之前设置的标志。

如下代码实现了设置指定文件的一位或者多位file status flags(文件状态标志)

void set_f1(int fd, int flags) /*flags are file status flags to turn on*/
{
int val;
if((val = fcntl(fd, F_GETFL, 0)) < 0) //获取文件状态标志值
{
fprintf(stderr, "fcntl get error for fd : %d", fd);
exit(-1);
}
val |= flags; //turn on flags
if( fcntl(fd, F_SETFL, val) < 0)//设置文件状态值
{
fprintf(stderr, "fcntl set error for fd : %d", fd);
exit(-1);
}
}


如果将中间的语句改成

val &= ~flags/*turn flags off 关闭相关位*/


在之后我们有函数
clr_f1
,这会在之后的example中使用。其使用了
AND
将val值和flags进行与操作。

在写操作(write)之前我们需要开启同步写标志,使用
set_f1(STDOUT_FILENO, O_SYNC);
这样每次write操作会在返回前确保数据写到了disk中。通常在Unix系统中,
write
操作仅仅将写的数据进行排队,实际的disk write操作会稍后执行。database(数据库)系统都会使用
O_SYNC
,因为数据库必须确保数据的一致性。

写入文件操作使用了O_SYNC标志比在
fsync
后使用
write
这种同步方式效率要高。因此使用
fcntl
改变文件属性是很有用的。此外
fcntl
可以用在我们描述无阻塞管道(nonblocking pipe Section 15.2)的时候。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: