DESCRIPTION
Given a pathname for a file, open() returns a file descriptor, a small, non-negative integer for use in subsequent system calls (read(2), write(2), lseek(2), fcntl(2), etc.). The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process.
The new file descriptor is set to remain open across an execve(2) (i.e., the FD_CLOEXEC file descriptor flag described in fcntl(2) is initially disabled). The file offset is set to the beginning of the file (see lseek(2)).
A call to open() creates a new open file description, an entry in the system-wide table of open files. This entry records the file offset and the file status flags (modifiable via the fcntl() F_SETFL operation). A file descriptor is a reference to one of these entries; this reference is unaffected if pathname is subsequently removed or modified to refer to a different file. The new open file description is initially not shared with any other process, but sharing may arise via fork(2).
The parameter flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file read-only, write-only, or read/write, respectively.
creat() is equivalent to open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.
RETURN VALUE
open() and creat() return the new file descriptor, or -1 if an error occurred (in which case, errno is set appropriately).
NOTES
Note that open() can open device special files, but creat() cannot create them; use mknod(2) instead.
On NFS file systems with UID mapping enabled, open() may return a file descriptor but e.g. read(2) requests are denied with EACCES. This is because the client performs open() by checking the permissions, but UID mapping is performed by the server upon read and write requests.
If the file is newly created, its st_atime, st_ctime, st_mtime fields (respectively, time of last access, time of last status change, and time of last modification; see stat(2)) are set to the current time, and so are the st_ctime and st_mtime fields of the parent directory. Otherwise, if the file is modified because of the O_TRUNC flag, its st_ctime and st_mtime fields are set to the current time.
ERRORS
Tag | Description |
---|---|
EACCES | The requested access to the file is not allowed, or search permission is denied for one of the directories in the path prefix of pathname, or the file did not exist yet and write access to the parent directory is not allowed. (See also path_resolution(2).) |
EEXIST | pathname already exists and O_CREAT and O_EXCL were used. |
EFAULT | pathname points outside your accessible address space. |
EISDIR | pathname refers to a directory and the access requested involved writing (that is, O_WRONLY or O_RDWR is set). |
ELOOP | Too many symbolic links were encountered in resolving pathname, or O_NOFOLLOW was specified but pathname was a symbolic link. |
EMFILE | The process already has the maximum number of files open. |
ENAMETOOLONG | |
pathname was too long. | |
ENFILE | The system limit on the total number of open files has been reached. |
ENODEV | pathname refers to a device special file and no corresponding device exists. (This is a Linux kernel bug; in this situation ENXIO must be returned.) |
ENOENT | O_CREAT is not set and the named file does not exist. Or, a directory component in pathname does not exist or is a dangling symbolic link. |
ENOMEM | Insufficient kernel memory was available. |
ENOSPC | pathname was to be created but the device containing pathname has no room for the new file. |
ENOTDIR | |
A component used as a directory in pathname is not, in fact, a directory, or O_DIRECTORY was specified and pathname was not a directory. | |
ENXIO | O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process has the file open for reading. Or, the file is a device special file and no corresponding device exists. |
EOVERFLOW | |
pathname refers to a regular file, too large to be opened; see O_LARGEFILE above. | |
EPERM | The O_NOATIME flag was specified, but the effective user ID of the caller did not match the owner of the file and the caller was not privileged (CAP_FOWNER). |
EROFS | pathname refers to a file on a read-only filesystem and write access was requested. |
ETXTBSY | |
pathname refers to an executable image which is currently being executed and write access was requested. | |
EWOULDBLOCK | |
The O_NONBLOCK flag was specified, and an incompatible lease was held on the file (see fcntl(2)). |
NOTE
Under Linux, the O_NONBLOCK flag indicates that one wants to open but does not necessarily have the intention to read or write. This is typically used to open devices in order to get a file descriptor for use with ioctl(2).
CONFORMING TO
SVr4, 4.3BSD, POSIX.1-2001. The O_NOATIME, O_NOFOLLOW, and O_DIRECTORY flags are Linux-specific. One may have to define the _GNU_SOURCE macro to get their definitions.
The (undefined) effect of O_RDONLY | O_TRUNC varies among implementations. On many systems the file is actually truncated.
The O_DIRECT flag was introduced in SGI IRIX, where it has alignment restrictions similar to those of Linux 2.4. IRIX has also a fcntl(2) call to query appropriate alignments, and sizes. FreeBSD 4.x introduced a flag of same name, but without alignment restrictions. Support was added under Linux in kernel version 2.4.10. Older Linux kernels simply ignore this flag. One may have to define the _GNU_SOURCE macro to get its definition.
BUGS
«The thing that has always disturbed me about O_DIRECT is that the whole interface is just stupid, and was probably designed by a deranged monkey on some serious mind-controlling substances.» Linus
Currently, it is not possible to enable signal-driven I/O by specifying O_ASYNC when calling open(); use fcntl(2) to enable this flag.
RESTRICTIONS
There are many infelicities in the protocol underlying NFS, affecting amongst others O_SYNC and O_NDELAY.
POSIX provides for three different variants of synchronised I/O, corresponding to the flags O_SYNC, O_DSYNC and O_RSYNC. Currently (2.1.130) these are all synonymous under Linux.
What is a System Call in Linux And How Does it Work with Examples
A system call is a function that allows a process to communicate with the Linux kernel. It’s just a programmatic way for a computer program to order a facility from the operating system’s kernel. System calls expose the operating system’s resources to user programs through an API (Application Programming Interface). System calls can only access the kernel framework. System calls are needed for all the services that need resources.
The Linux kernel is proprietary software that loads and operates on the device at the least potential stage. Its job is to organize all that happens on the machine, from the keyboard, disk drive, and network events to providing time slices for concurrent execution of different programs. The separation of software and hardware creates a secure bubble that improves protection and reliability. Unprivileged applications are unable to reach other program’s storage, and if one fails, the kernel suspends the process so that it does not damage the entire system.
Wafer Thin Wrapper:
The Linux system calls are not rendered explicitly to the kernel in certain programs. Almost all the programs use the basic C library and offer a lightweight but essential wrapper over the Linux system calls. The repository then provides the accompanying Linux machine call after ensuring that the feature parameters are translated into the right processor registers. Whenever the wrapper receives data from the system call, it analyses it and contributes it to the program clearly. Any machine-interactive operation in a program is ultimately converted into a system call. So, let’s have a look at some of them. There is a long list of Linux system calls which we can use in our Linux system. Here is the list of some common and mostly used Linux system calls.
Let’s discuss some of the Linux system calls using the C language in our article to get hands-on with it.
Open System Call:
We can use the “Open” system call in our Linux distribution to swiftly open the document, which we will specify in our code of C language. Launch the command terminal firstly. You can use the shortcut “Ctrl+Alt+T”. Suppose you have a text file “test.txt” in the home directory, and it contains some content in it. So, in the beginning, you have to create a new C type filename “new.c” in the terminal via nano editor. Therefore, try out the simple below nano instruction.
Now, the Nano editor has been launched. Type the below-shown code in it. We have two file descriptors in the code. Both the files can be opened using the open system call. The first descriptor contains a read call, and the second contains the write function. The first open call is opening the text file “test.txt” and saving its content into file descriptor “fd”. The second open system call is creating a file named “target”. The document “target” has been reimbursed to an “fd1” file descriptor. The write instruction is used to transcribe the bytes of data in the buffer. Tap “Ctrl+S” to save the code and hit the shortcut key “Ctrl+X” to quit the file.
Run the gcc compile instruction to compile this C code.
Let’s execute the code using the simple “a.out” query in the shell as follows:
The output data has been transmitted to the file “target”. Let’s check the “target” file using the “cat” query. The output screen is showing the 20 character data in the “target” file.
Exec System Call:
The exec system call is being cast off to run a file that is currently being processed. The former executable file is substituted, and the current file is operated whenever exec is called. By using an exec system call, we may assume that doing so will overwrite the old document or application in the loop with a fresh one. New software is used to override the whole process’s material. The document whose title is given in the statement whenever invoking exec() is substituted for the user information section that runs the exec() system call (). So open the command terminal and, using the nano editor, create a new C type file as follows:
The editor has been opened now. Write out the whole below C language code in it. There are three main libraries included in it. After that, the main function has been instantiated. The print statement has been showing the string data and the Process Id of the file “exp.c”. The getpid() function has been used for this purpose. Then we have a character type array with some values in it. The exec system call has been used to take the file name and the one-line above array as an argument. Now the file “hello.c” will be processed. After that, another print statement comes so far, but it will never be executed. Press “Ctrl+S” to save this file. Hit “Ctrl+X” to exit.
Now it’s time to create another c file, “hello.c” using the nano editor. Use the below query in the shell to do so.
Write the below code in it. This code contains two print statements in the main function. The first is only printing a string given in it, and the second one is printing the string while fetching the process ID of the currently used file, which is “hello.c”.
Let’s compile both files one after another using gcc.
When we execute the exp.c file, it will output the first print statement from the exp.c file and both the print lines from the hello.c file.
Conclusion:
We have elaborated on the whole concept of Linux system calls and how they can be used in your Linux system. We have used Ubuntu 20.04 while implementing this concept.
About the author
Aqsa Yasin
I am a self-motivated information technology professional with a passion for writing. I am a technical writer and love to write for all Linux flavors and Windows.