The use of DUP/DUP2 functions under Linux

Source: Internet
Author: User

The system calls DUP and dup2 to copy the file descriptor. The DUP returns a new file descriptor (the smallest number that is not used by the file descriptor). Dup2 can let the user specify the value of the returned file descriptor, and, if necessary, close to the value of NEWFD, which is often used to reopen or redirect a file descriptor.

His prototype is as follows:

#include <unsitd.h>

int dup (int oldfd);

int dup2 (int oldfd,int newfd);

Both DUP and dup2 are returned with the new descriptor. or return 1 and set the errno variable. The new and old descriptors share the offset (location), flags, and locks of the file, but do not share the CLOSE-ON-EXEC flag.

It is believed that most programmers who are programmed under Unix/linux have the super-classic "UNIX Environment Advanced Programming" (APUE) on hand. In this book, the author explained Dup/dup2 before, "file sharing", which is very helpful to understand dup/dup2. Here is a simple excerpt for use in the following analysis:
Stevens said:
(1) Each process has a record entry in the process table, and each record entry has an open File descriptor table, which can be treated as a vector that occupies one item per descriptor. associated with each file description typeface:
(a) The file descriptor flag.
(b) A pointer to a file table entry.
(2) The kernel maintains a single file table for all open files. Each file Table entry contains:
(a) file status flags (read, write, write-up, sync, non-blocking, etc.).
(b) The current amount of file displacement.
(c) A pointer to the V-node table entry for the file.
Icon:
File Descriptor Descriptor
------------
Fd0 0 | P0-------------> Documents table 0---------> Vnode0
------------
FD1 1 | P1-------------> Documents table 1---------> Vnode1
------------
FD2 2 | P2
------------
FD3 3 | P3
------------
... ...
... ...
------------

I. DUP and DUP2 within a single process
Assuming that process A has an open file descriptor, FD3, it has the following status

File descriptor for process a (before dup2)
------------
Fd0 0 | P0
------------
FD1 1 | P1-------------> Documents table 1---------> Vnode1
------------
FD2 2 | P2
------------
FD3 3 | P3-------------> Documents table 2---------> Vnode2
------------
... ...
... ...
------------

Called by the following:
N_FD = Dup2 (fd3, Stdout_fileno), the post-process status is as follows:

File descriptor for Process a (after dup2)
------------
Fd0 0 | P0
------------
N_FD 1 | P1------------
------------               \
FD2 2 | P2 \
------------                 _\|
FD3 3 | P3-------------> Documents table 2---------> Vnode2
------------
... ...
... ...
------------
The explanations are as follows:
N_FD = Dup2 (fd3, Stdout_fileno) means that N_FD shares a file table entry with FD3 (their file table pointers point to the same file table entry), N_FD position in the File descriptor table as Stdout_fileno, and the original Stdout_ The file table entry that Fileno points to is closed, which I think should be reflected clearly. As explained above, we can explain some of the questions raised in the CU:
(1) "is the first parameter of dup2 must be a valid filedes that has been opened?" "--answer: must.
(2) "dup2 The second parameter can be any valid range of Filedes value?" "--Answer: Yes, in Unix its value range is [0,255].

In addition, a good way to understand dup2 is to think of FD as a struct type, as shown in the graphic above, and we might as well define it as:
struct fd_t {
int index;
Filelistitem *ptr;
};
Then dup2 matches index, modifies PTR, and completes the dup2 operation.

When learning dup2, always encounter the word "redirect", Complete is a "from standard output to file redirection", after dup2 process A of any target for Stdout_fileno I/O operations such as printf, etc., its data will flow into the corresponding file FD3. Here is an example program:
#define TESTSTR "Hello dup2\n"
int main () {
int fd3;

FD3 = open ("Testdup2.dat", 0666);
if (FD < 0) {
printf ("Open error\n");
Exit (-1);
}

if (Dup2 (FD3, Stdout_fileno) < 0) {
printf ("Err in dup2\n");
}
printf (TESTSTR);
return 0;
}
The result is that you see "Hello dup2" in Testdup2.dat.

Second, re-redirect after recovery
There is such a post on the CU, that is, how to return to the original state after redirection? First, everyone can think of a file descriptor to save before redirection. So how to save it, like the following line?
int s_fd = Stdout_fileno;
int n_fd = dup2 (fd3, Stdout_fileno);
Or is that possible?
int s_fd = DUP (Stdout_fileno);
int n_fd = dup2 (fd3, Stdout_fileno);
Where is the difference between these two methods? The answer is that the second scenario is correct, and the analysis is as follows: In the first method, we only save the index in the "surface" equivalent to fd_t (as I explained earlier), and after calling Dup2, the file table entry that PTR points to is closed because the count value is zero. If we call Dup2 again (S_FD, FD3) It will go wrong (the reason for the error is explained above). And the second method we first make a copy, the state after the replication as shown:
File descriptor for process a (after DUP)
------------
Fd0 0 | P0
------------
FD1 1 | P1-------------> Documents table 1---------> Vnode1
------------                 /|
FD2 2 | P2/
------------             /
FD3 3 | P3-------------> Documents table 2---------> Vnode2
------------          /
S_FD 4 | P4------/
------------
... ...
... ...
------------

call dup2 after the state is:
Process a file descriptor (after dup2)
  ------------
fd0 0    | P0
  ------------
n_fd 1   | p1------------
  ------------                \
Fd2 2   | p2                  \
  --------- ---                _\|
Fd3 3   | p3-------------> File table 2---------> Vnode2
  ------------
s_fd 4    | P4-------------> Documents table 1---------> Vnode1
  ------------
...
... The semantics of
  ------------
DUP (FD) is to return a new file descriptor that shares a file table entry with FD. As in the after DUP diagram, S_FD and fd1 share File Table 1.

After you determine the second scenario, the redirected recovery is easy, just call Dup2 (S_FD, N_FD); The following is a complete example program:
#define TESTSTR "Hello dup2\n"
#define SIZEOFTESTSTR 11

int main () {
int fd3;
int s_fd;
int n_fd;

FD3 = open ("Testdup2.dat", 0666);
if (Fd3 < 0) {
printf ("Open error\n");
Exit (-1);
}


S_FD = DUP (Stdout_fileno);
if (S_FD < 0) {
printf ("Err in dup\n");
}


N_FD = Dup2 (fd3, Stdout_fileno);
if (N_FD < 0) {
printf ("Err in dup2\n");
}
Write (Stdout_fileno, teststr, SIZEOFTESTSTR);


if (Dup2 (S_FD, N_FD) < 0) {
printf ("Err in dup2\n");
}
Write (Stdout_fileno, teststr, SIZEOFTESTSTR);
return 0;
}
Note that I'm using the Write library function without buffering when I'm outputting data, and if I use printf with buffers, the end result is two lines of "Hello dup2" on the screen, And the file Testdup2.dat empty, because the buffer mischief, because the final target is the screen, so the program will finally output the contents of the buffer to the screen.


Iii. the dup/dup2 between father and son processes
The same file descriptor for the child process and the parent process that is called by the fork is shared with the same file table entry, as shown in:
File descriptor for parent process a
------------
Fd0 0 | P0
------------
FD1 1 | P1-------------> Documents table 1---------> Vnode1
------------                            /|\
FD2 2 | P2 |
------------                            |
|
File descriptor for child Process B |
------------                             |
Fd0 0 | P0 |
------------                             |
FD1 1 | P1---------------------|
------------
FD2 2 | P2
------------
So the proper use of dup2 and DUP can create a "bridge of communication" between father and son processes. Not detailed here.

Iv. Summary
Flexible use of dup/dup2 can bring you a lot of powerful functions, spent some time to summarize the above so many, do not know whether their understanding is thorough, can only be explored in the practice of the future slowly.

The use of DUP/DUP2 functions under Linux

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.