Introduction to fcntl function

    The fcntl function can change the attributes of an already opened file.
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* int arg */);
                    /* Return value: if successful, it depends on cmd; otherwise, return -1 */

    In the examples in this section, the third parameter is always an integer, but when record locks are described later, it is a pointer to a structure.
    The fcntl function has the following five functions:
    (1) Copy an existing descriptor (cmd = F_DUPFD / F_DUPFD_CLOEXEC).
    (2) Get/set file descriptor flags (cmd = F_GETFD / F_SETFD).
    (3) Get/set file status flag (cmd = F_GETFL / F_SETFL).
    (4) Get/set asynchronous I/O ownership (cmd = F_GETOWN / F_SETOWN).
    (5) Get/set record lock (cmd = F_GETLK / F_SETLK / F_SETLKW).
    The first 8 of the 11 cmds will be explained here, and the last 3 will be introduced later when the record lock is introduced. We will discuss the file descriptor flags associated with each file descriptor in the process table entry and the file status flags in each file table entry.
    F_DUPFD: Duplicate file descriptor fd. The new file descriptor is returned as the function value, which is the smallest value of the descriptors that have not been opened that is greater than or equal to the value of the third parameter (taken as an integer value), and it shares the same file table entry with fd. However, it has its own set of file descriptor flags, and its FD_CLOEXEC file descriptor flag is cleared (which means the descriptor remains valid on exec. Many existing programs that work with file descriptor flags do not use Constant FD_CLOEXEC, but set this flag to 0 (system default, do not close on exec) or 1 (close on exec)).
    F_DUPFD_CLOEXEC: Duplicate the file descriptor, set the value of the FD_CLOEXEC file descriptor flag associated with the new descriptor, and return the new file descriptor.
    F_GETFD: The file descriptor flag corresponding to fd is returned as the function value. Currently only one file descriptor flag, FD_CLOEXEC, is defined.
    F_SETFD: Set the file descriptor flag corresponding to fd. The new flag value is set by the 3rd parameter (taken as an integer value).
    F_GETFL: The file status flag corresponding to fd is returned as the function value. Unfortunately, the five file status flags (O_RDONLY, O_WRONLY, O_RDWR, O_EXEC, and O_SEARCH) in the open function do not occupy one bit each, and these five values ​​are mutually exclusive, and a file can only be accessed by one of them. Therefore, the access mode bits must first be obtained with the mask word O_ACCMODE, and then the result is compared with each of these 5 values.
    F_SETFL: Set the file status flag to the value of the third parameter (taken as an integer value). The few flags that can be changed are: O_APPEND, O_NONBLOCK, O_SYNC, O_DSYNC, O_RSYNC, O_FSYNC, and O_ASYNC.
    F_GETOWN: Get the process ID or process group ID currently receiving SIGIO and SIGURG signals.
    F_SETOWN: Set the process ID or process group ID that receives SIGIO and SIGURG signals. A positive arg specifies a process ID, and a negative arg represents a process group ID equal to the absolute value of arg.
    The following example can be used to print the file status flags selected by the specified file descriptor.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main(int argc, char *argv[]){
	int val;

	if(argc != 2){
		printf("usage: %s <descriptor>\n", argv[0]);	
		exit(1);
	}

	if((val=fcntl(atoi(argv[1]), F_GETFL, 0)) < 0){
		printf("fcntl() error for fd %s\n", argv[1]);
		exit(2);
	}

	switch(val & O_ACCMODE){
		case O_RDONLY:
			printf("read only");
			break;
		case O_WRONLY:
			printf("write only");
			break;
		case O_RDWR:
			printf("read write");
			break;
		default:
			printf("unknown access mode.");
	}

	if(val & O_APPEND)
		printf(", append");
	if(val & O_NONBLOCK)
		printf(", nonblocking");
	if(val & O_SYNC)
		printf(", synchronous writes");

#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
	if(val & O_FSYNC)
		printf(", synchronous writes");
#endif
	
	putchar('\n');
	exit(0);
}

    Here is the result from bash (with other shells the result may be different):
$./a.out 0 < /dev/tty
read only
$./a.out 1 > temp.foo
$cat temp.foo
write only
$./a.out 2 2>>temp.foo
write only, append
$./a.out 5 5<>temp.foo # means to open the file temp.foo on file descriptor 5 for reading and writing
read write

    You must be careful when modifying the file descriptor flag or file status flag. You must first get the current flag value, then modify it as expected, and finally set the new flag value. You can't just execute the F_SETFD or F_SETFL command, which will turn off the previously set flag bit. . The following is an example of a function that sets one or more file status flags on a file descriptor:
#include <stdlib.h>
#include <fcntl.h>

void set_fl(int fd, int flags){	// flags are file status flags to turn on.
	int val;
	if((val=fcntl(fd, F_GETFL, 0)) < 0){
		printf("fcntl F_GETFL error\n");
		exit(2);
	}

	val |= flags;	// turn on flags
	
	if(fcntl(fd, F_SETFL, val) < 0){
		printf("fcntl F_SETFL error\n");
		exit(2);
	}
}

void clr_fl(int fd, int flags){	// flags are file status flags to turn off.
	int val;
	if((val=fcntl(fd, F_GETFL, 0)) < 0){
		printf("fcntl F_GETFL error\n");
		exit(2);
	}

	val &= ~flags;	// turn flags off
	
	if(fcntl(fd, F_SETFL, val) < 0){
		printf("fcntl F_SETFL error\n");
		exit(2);
	}
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326228146&siteId=291194637
Recommended