Maarten Bruins
asked on
Understanding dup2 (C System Call)
dup2(int oldfd, int newfd);
This is an equivalent of:
close(int newfd);
dup(int oldfd);
By closing "newfd" first, it becomes the lowest-numbered unused file descriptor (normally). Because of that the oldfd is copied to newfd (dup system call). So far, everything is clear.
Now see: http://codewiki.wikidot.com/c:system-calls:dup2
dup2 is a system call similar to dup in that it duplicates one file descriptor, making them aliases, and then deleting the old file descriptor.
Actually I don't think the old file descriptor will be deleted?
See: http://man7.org/linux/man-pages/man2/dup.2.html
After a successful return, the old and new file descriptors may be used interchangeably.
If the old file descriptor will be deleted, then they would not say something like that. Is wikidot.com just wrong about this?
I think the author was trying to keep the description short and didn't have a good word to use instead of "delete". "delete" isn't 100% accurate, neither is "closed" as more happens than just closing the FD. "Overwritten" has implications that need clarification.
If you think about it as calling dup2() on STDIN (fd 0), the new entry replaces the old one so that I/O against what used to be STDIN now happens against a different file/device. That's exactly what redirection does and how the shell implements redirection.
Kent
If you think about it as calling dup2() on STDIN (fd 0), the new entry replaces the old one so that I/O against what used to be STDIN now happens against a different file/device. That's exactly what redirection does and how the shell implements redirection.
Kent
ASKER
I also considered "delete" instead of "close", but only at the beginning one descriptor is closed. The "coming" new one is closed to make it the lowest-numbered unused file descriptor, so it can become the new one. But they are saying:
after making them aliases. So when replacing "delete" by "close" it's still seems incorrect.
and then ...
after making them aliases. So when replacing "delete" by "close" it's still seems incorrect.
ASKER
@Kent: Then how you explan the "and then", after making them aliases? Anyway delete or close or whatever are wrong there. Nothing happens anymore after the dup() call. So after they are aliases, nothing happens anymore. It's just dup2 = close + dup + nothing more. So "and then..." is incorrect anyway if you would ask me (in any form).
I understand your argument. It might have made the documentation more clear.
When your program starts, it "knows" of 3 FDs, one each for STDIN, STDOUT, and STDERR. In a terminal environment they typically reference the keyboard and monitor. In a batch environment they reference other files or devices. Let's discuss it as a program running in a terminal environment.
The unix kernel maintains a list of all open files and devices. If you and I are simultaneously running programs on an otherwise idle server it's conceivable that the only entries in the kernel table is for STDIN, STDOUT, and STDERR that are mapped to the terminal devices. (In reality, there will be other files open, such as system logs, but let's ignore them.) Let's also assume that STDIN, STDOUT, and STDERR were created in the kernel in that order. So with your program fd[0] contains a 0, indicating the first kernel entry. fd[1] contains a 1, and fd[2] contains a 2.
Your program then opens another file. fd[3] in your program space now contains a 3 as it's the next item in the kernel.
My program now opens another file. fd[3] in my program space now contains a 4 as the position in the kernel table is slot 4.
That's a long way to explain that an fd is just an integer and how a value is assigned.
Most user programs will call dup(). It would be unusual to develop something that calls dup2().
I found a pretty good example of how any why a program would use dup2().
http://www.cs.loyola.edu/~jglenn/702/S2005/Examples/dup2.html
Take a look at the examples.
Kent
When your program starts, it "knows" of 3 FDs, one each for STDIN, STDOUT, and STDERR. In a terminal environment they typically reference the keyboard and monitor. In a batch environment they reference other files or devices. Let's discuss it as a program running in a terminal environment.
The unix kernel maintains a list of all open files and devices. If you and I are simultaneously running programs on an otherwise idle server it's conceivable that the only entries in the kernel table is for STDIN, STDOUT, and STDERR that are mapped to the terminal devices. (In reality, there will be other files open, such as system logs, but let's ignore them.) Let's also assume that STDIN, STDOUT, and STDERR were created in the kernel in that order. So with your program fd[0] contains a 0, indicating the first kernel entry. fd[1] contains a 1, and fd[2] contains a 2.
Your program then opens another file. fd[3] in your program space now contains a 3 as it's the next item in the kernel.
My program now opens another file. fd[3] in my program space now contains a 4 as the position in the kernel table is slot 4.
That's a long way to explain that an fd is just an integer and how a value is assigned.
Most user programs will call dup(). It would be unusual to develop something that calls dup2().
I found a pretty good example of how any why a program would use dup2().
http://www.cs.loyola.edu/~jglenn/702/S2005/Examples/dup2.html
Take a look at the examples.
Kent
ASKER
But now you're just explaining what dup and dup2 do in general? I think I know pretty well how they are working and that's why I think that wikidot.com is wrong about it, independent of how you look at it (so wrong in any form).
Another example of dup2, see: http://www.rozmichelle.com/pipes-forks-dups/#attachment_7362
But this question is mainly about this sentence:
This is just incorrect in any form, right? Or how you're seeing that sentence if you think it's still pretty okay?
Another example of dup2, see: http://www.rozmichelle.com/pipes-forks-dups/#attachment_7362
But this question is mainly about this sentence:
dup2 is a system call similar to dup in that it duplicates one file descriptor, making them aliases, and then deleting the old file descriptor.
This is just incorrect in any form, right? Or how you're seeing that sentence if you think it's still pretty okay?
Perhaps I am missing something but all I see dup2 as doing is closing and opening a file descriptor in a single atomic operation (as per the docs). On that basis, I think the terminology in wikidot.com is not really accurate, but I can excuse the term.
I understand it, but like you, think it's not phrased very well.
Look at this part of the redirect.c example
The program opens file "scores" and calls dup2() to assign STDIN such that reads from STDIN read from "scores".
Dup2 duplicates the fd associated with "scores" and deletes the fd that was associated with STDIN prior to the call. In truth, it simply overwrites the entry after closing the file. But I can (kind of ) understand why the author used "deleted".
Look at this part of the redirect.c example
in = open("scores", O_RDONLY);
// replace standard input with input file
dup2(in, 0);
The program opens file "scores" and calls dup2() to assign STDIN such that reads from STDIN read from "scores".
Dup2 duplicates the fd associated with "scores" and deletes the fd that was associated with STDIN prior to the call. In truth, it simply overwrites the entry after closing the file. But I can (kind of ) understand why the author used "deleted".
ASKER
@Kent: You're saying:
This is not true. Dup2 first closes newfd, and then it duplicates oldfd ("in" in your example). So you forgot about "close" before the duplication. After the duplication, nothing will be closed or deleted.
Dup2 duplicates the fd associated with "scores" and deletes the fd that was associated with STDIN prior to the call.
This is not true. Dup2 first closes newfd, and then it duplicates oldfd ("in" in your example). So you forgot about "close" before the duplication. After the duplication, nothing will be closed or deleted.
We're getting off track here.
In trying to explain the use of the word "delete" the call to close() isn't relevant. The process makes access to the file/device originally referenced by STDIN inaccessible though that fd. The device or file may still be accessible if another fd references it, but access via STDIN is logically deleted.
In trying to explain the use of the word "delete" the call to close() isn't relevant. The process makes access to the file/device originally referenced by STDIN inaccessible though that fd. The device or file may still be accessible if another fd references it, but access via STDIN is logically deleted.
ASKER
Ah okay, now I understand what you mean. In other words, one reference count to that device/file is deleted.
But if they were trying to say that, then it was a really bad try, because the reference count is already one less at the moment the close function is called. Then that device/file already has no access anymore to STDIN, so in the end it is about close() and close() is relevant.
But if they were trying to say that, then it was a really bad try, because the reference count is already one less at the moment the close function is called. Then that device/file already has no access anymore to STDIN, so in the end it is about close() and close() is relevant.
Generally, the linux/unix documentation is pretty good, but it usually looks more like reference material (where you need to know the subject and are looking for a refresher) instead of student materials (where you're learning from scratch).
ASKER
Why it's so difficult to admit that it's just a mistake and that they actually just have to correct it? Even if it's reference material, it's just bad.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Ah okay, thanks! Then at least I know for sure now that it's just incorrect.
The man page is correct, the wikidot.com is wrong...
The man page never uses the word delete....
From the gnu manpages:
In general accurate man page site: https://linux.die.net/man/2/dup
slightly different description still
Source of manpage:
And here you can help maintaining them:
https://www.kernel.org/doc/man-pages/contributing.html
The man page never uses the word delete....
From the gnu manpages:
dup2()
The dup2() system call performs the same task as dup(), but instead of using the lowest-numbered unused file descriptor, it uses the file
descriptor number specified in newfd. If the file descriptor newfd was previously open, it is silently closed before being reused.
The steps of closing and reusing the file descriptor newfd are performed atomically. This is important, because trying to implement equiva‐
lent functionality using close(2) and dup() would be subject to race conditions, whereby newfd might be reused between the two steps. Such
reuse could happen because the main program is interrupted by a signal handler that allocates a file descriptor, or because a parallel thread
allocates a file descriptor.
Note the following points:
* If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.
* If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.
In general accurate man page site: https://linux.die.net/man/2/dup
slightly different description still
Source of manpage:
COLOPHON
This page is part of release 4.16 of the Linux man-pages project. A description of the project, information about reporting bugs, and the
latest version of this page, can be found at https://www.kernel.org/doc/man-pages/. (nlu+10
And here you can help maintaining them:
https://www.kernel.org/doc/man-pages/contributing.html
I guess wikidot is using the term "delete" instead of "close". I am not sure why they refer to "deleting the old file descriptor" unless they are referring to the one that newfd could potentially be referencing but you no longer require. It's unclear to me.