fcntl Linux

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)的时候。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值