Can someone explain what dup() in C does?
Asked Answered
C

8

28

I know that dup, dup2, dup3 "create a copy of the file descriptor oldfd"(from man pages). However I can't digest it.

As I know file descriptors are just numbers to keep track of file locations and their direction(input/output). Wouldn't it be easier to just

fd=fd2;

Whenever we want to duplicate a file descriptor?

And something else..

dup() uses the lowest-numbered unused descriptor for the new descriptor.

Does that mean that it can also take as value stdin, stdout or stderr if we assume that we have close()-ed one of those?

Contrarious answered 22/10, 2011 at 18:12 Comment(1)
For the first question you need to remember that the kernel keeps track of the number of open file handles. dup is your way of telling the kernel that you want it to keep track track of another one of those file handles (referring to the same file) until you close it.Whirl
C
25

Just wanted to respond to myself on the second question after experimenting a bit.

The answer is YES. A file descriptor that you make can take a value 0, 1, 2 if stdin, stdout or stderr are closed.

Example:

close(1);     //closing stdout
newfd=dup(1); //newfd takes value of least available fd number

Where this happens to file descriptors:

0 stdin     .--------------.     0 stdin     .--------------.     0 stdin
1 stdout   =|   close(1)   :=>   2 stderr   =| newfd=dup(1) :=>   1 newfd
2 stderr    '--------------'                 '--------------'     2 stderr
Contrarious answered 24/10, 2011 at 14:49 Comment(2)
A question arose again: How can I dup() a file descriptor that I already closed?Contrarious
From the definition, dup() uses the lowest-numbered unused descriptor for the new descriptor. And when you close a file descriptor, this means that it is available for use.Frasch
H
16

A file descriptor is a bit more than a number. It also carries various semi-hidden state with it (whether it's open or not, to which file description it refers, and also some flags). dup duplicates this information, so you can e.g. close the two descriptors independently. fd=fd2 does not.

Hopping answered 22/10, 2011 at 18:54 Comment(2)
This. The "number" is an index into a data structure maintained by the kernel. The dup family of function clone the state of a node in that data structure and hand you the index to the new node.Sienna
@dmckee: "Kernel" and "index" are implementation details. There's some data associated with "the number" which cannot be manipulated directly by the program, and which is cloned by dup(). That's all the programmer needs to know. By the way it is not a very interesting piece of data, it's just a couple of flags and an index to the really interesting data (the open file description) which is not cloned by dup().Hopping
Y
9

The single most important thing about dup() is it returns the smallest integer available for a new file descriptor. That's the basis of redirection:

int fd_redirect_to = open("file", O_CREAT);
close(1); /* stdout */
int fd_to_redirect = dup(fd_redirect_to); /* magically returns 1: stdout */
close(fd_redirect_to); /* we don't need this */

After this anything written to file descriptor 1 (stdout), magically goes into "file".

Yapon answered 3/8, 2013 at 8:4 Comment(1)
Assuming (not unreasonably) that file descriptor 0 is currently open. Support for redirections such as 200>somefile is very inconvenient without dup2() (or dup3(), but that is a recent addition to systems).Skeen
S
7

Let's say you're writing a shell program and you want to redirect stdin and stdout in a program you want to run. It could look something like this:

fdin = open(infile, O_RDONLY);
fdout = open(outfile, O_WRONLY);
// Check for errors, send messages to stdout.
...
int pid = fork(0);
if(pid == 0) {
    close(0);
    dup(fdin);
    close(fdin);
    close(1);
    dup(fdout);
    close(fdout);
    execvp(program, argv);
}
// Parent process cleans up, maybe waits for child.
...

dup2() is a little more convenient way to do it the close() dup() can be replaced by:

dup2(fdin, 0);
dup2(fdout, 1);

The reason why you want to do this is that you want to report errors to stdout (or stderr) so you can't just close them and open a new file in the child process. Secondly, it would be a waste to do the fork if either open() call returned an error.

Smile answered 22/10, 2011 at 18:30 Comment(0)
B
4

Example:

close(1);     //closing stdout
newfd=dup(1); //newfd takes value of least available fd number

Where this happens to file descriptors:

0 stdin     .--------------.     0 stdin     .--------------.     0 stdin
1 stdout   =|   close(1)   :=>   2 stderr   =| newfd=dup(1) :=>   1 newfd
2 stderr    '--------------'                 '--------------'     2 stderr

A question arose again: How can I dup() a file descriptor that I already closed?

I doubt that you conducted the above experiment with the shown result, because that would not be standard-conforming - cf. dup:

The dup() function shall fail if:

[EBADF]
The fildes argument is not a valid open file descriptor.

So, after the shown code sequence, newfd must be not 1, but rather -1, and errno EBADF.

Bryna answered 28/5, 2018 at 9:10 Comment(0)
F
2

see this page, stdout can be aliased as dup(1)...

Foreskin answered 22/10, 2011 at 18:19 Comment(0)
F
2

Just a tip about "duplicating standard output".

On some Unix Systems (but not GNU/Linux)

fd = open("/dev/fd/1", O_WRONLY);

it is equivalent to:

fd = dup(1);
Foreman answered 3/10, 2016 at 17:52 Comment(0)
G
-1

dup() and dup2() system call

•The dup() system call duplicates an open file descriptor and returns the new file descriptor.

•The new file descriptor has the following properties in common with the original file descriptor: 1. refers to the same open file or pipe. 2. has the same file pointer -- that is, both file descriptors share one file pointer. 3. has the same access mode, whether read, write, or read and write.

• dup() is guaranteed to return a file descriptor with the lowest integer value available.It is because of this feature of returning the lowest unused file descriptor available that processes accomplish I/O redirection.

int dup(file_descriptor)

int dup2(file_descriptor1, file_descriptor2)

Goolsby answered 22/10, 2018 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.