dup2 System Call in C

dup2 System Call in C
The dup2() system function is used to create a copy of an existing file descriptor. In Linux, there are 3 standard file descriptors. They are:

stdin: This is the standard input file descriptor. It is used to take input from the terminal by default. scanf(), getc() etc functions uses stdin file descriptor to take user inputs. The stdin file descriptor is also represented by the number 0.

stdout: This is the standard output file descriptor. It is used to print something to the console/terminal by default. The widely used printf() function uses stdout to print your desired output to the console/terminal. The stdout file descriptor is also represented by the number 1.

stderr: This is the standard error file descriptor. It does the same thing as the stdout file descriptor. The stderr file descriptor is used to print error messages on the console/terminal. The only difference is if you use stderr file descriptor to print the error messages, and stdout file descriptor to print normal outputs, then you can later separate them. For example, you can redirect the error messages to a file and normal outputs to the console or another file. The stderr file descriptor is also represented by the number 2.

Other than these 3 file descriptors, you can create additional file descriptors in C. To create a new file descriptor, you can use the open() function in C. The open() function opens a new file, creates a file descriptor for that file and attaches a number other than 0, 1, 2 to the file descriptor.

Once you open a file using open() function, you can use the read() and write() function to read and write to the newly created file descriptor.

Now, imagine a situation where you want to read from a specific file using scanf() or getc() function and write to another file using printf() function. This is not the default behavior of the scanf(), getc() and printf() functions as I explained earlier. By default, scanf() and getc() function uses stdin and printf() uses stdout and there is no way to tell these functions to use other file descriptors. So, to alter this default behavior, you have to replace the stdin and stdout file descriptors with your desired file descriptors. This is what the dup2() system function does. The dup2() function copies a file descriptor to another file descriptor.

dup2() Syntax and Return Value:

The syntax of dup2() function is:

int dup2(int old_file_descriptor, int new_file_descriptor);

dup2() function copies the old_file_descriptor into the new_file_descriptor. If the new_file_descriptor already exists, then it’s automatically closed and then the old_file_descriptor is copied to it.

On success, the dup2() function returns the new file descriptor. If an error occurs, dup2() returns -1.

The dup2() function is defined in the header file unistd.h.

You must include the header unistd.h in your C source file in order to use the dup2() function as follows:

#include <unistd.h>

For more information, check the man page of dup2() with the following command:

$ man dup2

Example 1:

Create a new C source file 01_dup2.c and type in the following lines of codes in the file.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
 
int main(void) {
  int number1, number2, sum;
 
  int input_fds = open("./input.txt", O_RDONLY);
 
  if(dup2(input_fds, STDIN_FILENO) < 0) {
    printf("Unable to duplicate file descriptor.");
    exit(EXIT_FAILURE);
  }
 
  scanf("%d %d", &number1, &number2);
 
  sum = number1 + number2;
 
  printf("%d + %d = %dn", number1, number2, sum);
 
  return EXIT_SUCCESS;
}

Now, create a new file input.txt in the same directory and type in the following line in it.

15 41

The main objective of this program is to read 2 integer numbers from the input.txt file using scanf() function, add them and print the sum.

First, I included the required header files with the following lines of codes.

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

In the main() function, I defined the required variables.

int number1, number2, sum;

Then, I opened the file input.txt in read only mode (O_RDONLY) using the open() function and stored the file descriptor in the variable input_fds.

int input_fds = open("./input.txt", O_RDONLY);

Once I have the file descriptor of the input.txt file, I copied the file descriptor into the standard input file descriptor STDIN_FILENO (0) using dup2() function. The file descriptor of input.txt is now the default stdin file descriptor.

dup2(input_fds, STDIN_FILENO)

I could also write the dup2() function as follows. The result would be the same. STDIN_FILENO holds the value 0, which is the value of the stdin file descriptor.

dup2(input_fds, 0)

I also checked for dup2() errors with the following lines. If an error do occur, the program is set to print an error message and exit.

if(dup2(input_fds, STDIN_FILENO) < 0) {
  printf("Unable to duplicate file descriptor.");
  exit(EXIT_FAILURE);
}

Then, I used scanf() to scan 2 numbers from the input.txt file.

scanf("%d %d", &number1, &number2);

Then, I added the numbers and printed the sum on the console/terminal, the default stdout.

sum = number1 + number2;
printf("%d + %d = %dn", number1, number2, sum);

As you can see, I got the expected output once I run the program.

Example 2:

Create a new C source file 02_dup2.c and type in the following lines of codes in the file.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
  int number1, number2, sum;
  int input_fds = open("./input.txt", O_RDONLY);
  int output_fds = open("./output.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
  dup2(input_fds, STDIN_FILENO);
  dup2(output_fds, STDOUT_FILENO);
  scanf("%d %d", &number1, &number2);
  sum = number1 + number2;
  printf("%d + %d = %dn", number1, number2, sum);
  return EXIT_SUCCESS;
}

Now, create a new file input.txt in the same directory and type in the following line in it.

15 41

In this program, I did the same thing as in Example 1. The only difference is that I created a new file output.txt and used the file descriptor of output.txt as the default stdout file descriptor using the dup2() function. Now, all the output of the printf() function will be written to the output.txt file.

I created a new file and stored the file descriptor in output_fds variable.

int output_fds = open("./output.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);

I also copied the output_fds file descriptor to the stdout file descriptor. I used the predefined constant STDOUT_FILENO.

dup2(output_fds, STDOUT_FILENO);

STDOUT_FILENO contains the value 1 (the default file descriptor value of stdout). So, I could rewrite dup2() function call as follows. It would give the same results.

dup2(output_fds, 1);

The rest of the program is the same. As you can see, once I run the program, it does not print anything on the console/terminal.

But, the program created a new file output.txt file.

As you can see, the output is written to the file output.txt.

If you want to write all errors (stderr) to another file, then you can also copy a file descriptor to stderr file descriptor as follows.

dup2(error_fds, STDERR_FILENO);

So, that’s how you use the dup2() system call in C. Thanks for reading this article.

Related Posts
Leave a Reply

Your email address will not be published.Required fields are marked *