Dup2 File Descriptor

0 views
Skip to first unread message

Brittany Bhadd

unread,
Aug 5, 2024, 3:56:32 AM8/5/24
to substranwafe
dup2doesn't return void, it returns int, so you should check its return code. If dup2 were failing for some reason and that was the problem then you wouldn't know about it. That being said, dup2 normally always works.

There is one corner case that could cause what you are seeing: if sockfd is already 0. Then you'd be dup2ing 0 to 0 and then closing 0, leaving you with no file descriptor at all. Therefore it's good practice before using dup2 to check whether or not the file descriptor you are trying to renumber is already numbered correctly. But again, this is not likely in your case than sockfd is 0 to begin with.


So I understand that dup2() in this case will close 0 (standard keyboard input for stdin), it will then make stdin read from the file data, but why would you then close(fd)? I thought fd was what stdin is reading from now?


open creates a reference-counted file description (some struct) in the kernel and the returned file descriptor is kind of like a pointer to it (one of the counted references) from userspace, unless it's a negative value in which case open failed. dup2(fd,0) makes 0 also point to the same file description (unless you passed a negative fd or unless you're out of filedescriptors). If your goal was to have 0 point to the filedescription, you can now get rid of the old "pointer"/filedescriptor so you don't waste filedescriptor slots (a process can only allocate a limited number).


(Additionally closing the last reference to a filedescription may lead to certain desirable actions such as the file being dropped if it's an unliked file or the read end of a pipe receiving EOF if you just closed the last reference to the corresponding write end. Unnecessary references (filedescriptors) lying around get in the way of this.)


Implementations may use file descriptors that must be inherited into child processes for the child process to remain conforming,such as for message catalog or tracing purposes. Therefore, an application that calls dup2() with an arbitrary integer forfildes2 risks non-conforming behavior, and dup2() can only portably be used to overwrite file descriptor values thatthe application has obtained through explicit actions, or for the three file descriptors corresponding to the standard filestreams. In order to avoid a race condition of leaking an unintended file descriptor into a child process, an application shouldconsider opening all file descriptors with the FD_CLOEXEC bit set unless the file descriptor is intended to be inherited acrossexec.


The dup2() system call is similar to dup() but the basic difference between them is that instead of using the lowest-numbered unused file descriptor, it uses the descriptor number specified by the user.

Syntax:




A tricky use of dup2() system call: As in dup2(), in place of newfd any file descriptor can be put. Below is a C implementation in which the file descriptor of Standard output (stdout) is used. This will lead all the printf() statements to be written in the file referred by the old file descriptor.


You can duplicate a file descriptor, or allocate another filedescriptor that refers to the same open file as the original. Duplicatedescriptors share one file position and one set of file status flags(see File Status Flags), but each has its own set of file descriptorflags (see File Descriptor Flags).


The return value from fcntl with this command is normally the valueof the new file descriptor. A return value of -1 indicates anerror. The following errno error conditions are defined forthis command:


ENFILE is not a possible error code for dup2 becausedup2 does not create a new opening of a file; duplicatedescriptors do not count toward the limit which ENFILEindicates. EMFILE is possible because it refers to the limit ondistinct descriptor numbers in use in one process.


Here is an example showing how to use dup2 to do redirection.Typically, redirection of the standard streams (like stdin) isdone by a shell or shell-like program before calling one of theexec functions (see Executing a File) to execute a newprogram in a child process. When the new program is executed, itcreates and initializes the standard streams to point to thecorresponding file descriptors, before its main function isinvoked.


A powerful capability in the shell is the ability to treat terminal input and outputinterchangeably with file input/output for most commands. For example, to savethe list of all files ending with .c into a file called files.txt,one can run:


In UNIX systems (and derivatives), open files and devices are identified by file descriptors. A file descriptor is a small integerthat, internally, is simply an index into a per-process table of informationabout open files.Each process expects to have three open file descriptorsupon startup.The standard input, file descriptor 0, is used as the default input source.Typically, this is data that the user enters via the keyboard to thevirtual terminal (window running a shell) but may be redirected to another source such as a file (through input redirection) or the outputof another program (via a pipe).The standard output, file descriptor 1, is used as the default output source.This, too, is the user's virtual terminal by default. The standard error, file descriptor 2, is an alternate output source thatis typically used for sending error messages. Typically, this is thesame as the standard output. However, if the standard output is redirected,the standard error is still the terminal so that the user can see any error messages that are generated by the program. The user can redirectthis on the shell via the 2> redirector:


The user can also direct the standard error to the same stream as standardoutput even if the standard output is redirected with this syntax, which explicitly states that the standard error is redirected to file descriptor 1::


These functions are not system calls and are part of thestdio package. The stdio package isa set of functions that provides user-level buffering for inputand output. File descriptors are not accessed directly sincedoing so will bypass any buffering that is done by the library.Instead, the libary keeps track of open files with FILEstructures. The variables stdin, stdout, andstderr are pointers to FILE structuresthat correspond to the standard input, output, and error streams.Internally, the stdio library of course uses file descriptors alongwith read, write, open, and closesystem calls since those are theonly facilities provided by the operating system.


A custom program is welcome to open or create any files it wishes to anduse the resultant file descriptor for accessing that file. Thereis rarely any particular need to change the standard input, standard output,or standard error. However, in cases where other programs need to be run,one's ability to change where data is read from or written to is oftenlimited to redefining the standard input and output streams. As we've seen, the shell uses this facility extensively for providing I/Oredirection and pipe capabilities to programs it runs.


The kernel allows us to do this via the dup2 system call.The dup2(int f_orig, int f_new) system calltakes two file descriptors as parameters and duplicates the first one(f_orig) onto the second one (f_new). If the secondfile descriptor was referencing a file, that file is closed. Afterthe system call, both file descriptors are valid references to the file.


This is a really small program that illustrates how dup2 works.We get a file name from the command line and create it as a new file, gettinga file descriptor for it.We then write something to the standard output using printf and the stdio library.After that, we use dup2 to copy the file descriptor for the new file (newfd)onto the standard output file descriptor (1). Any printf functions will continue to go to the standard output, but that has nowbeen changed to the file we just opened.


The more useful example of dup2 is input or output (or both) redirection.Here we get the name of the output file from the command line as before and set that to be the standard outputbut now execute a command (ls -al / in this example). The command sends its output to the standardoutput stream, which is now the file that we created.


The above example uses execvp, which overwrites the current process with the new program.If we want the command to run in a separate process while sending its output to the file that we created,we can simply fork a new process. Note that we perform our dup2 call in the childso that we do not overwrite the standard output of the parent. We also close the standard input sincewe do not want the forked process trying to read from there (the ls command in this examplewill not but other programs might). Finally, the parent waits for the child process to terminate beforecontinuing.


This entire discussion focussed on the dup2 system call. Given that name,one cannot help but wonder what happened to dup1. There actually is adup system call and it predates dup by many years.Unlike dup2, dup takes a single parameter: the open file descriptor.It then duplicates it onto the lowest numbered file descriptor that is currentlynot used by that process and returns the number of that file descriptor.


A process starts off with the first three file descriptors in use (0, 1, and 2; standard in, standard out, and standard error, respectively). To duplicate a new file descriptor onto, say, the standard output, you would close the standardoutput file descriptor (1) and then call dup. Since the lowest unused file descriptoris now 1, dup will duplicate the file descriptor to file descriptor 1.


There are two downsides to using dup. First, you have to close the file descriptor thatwill be the target of duplication so that it becomes unused. This means that you will be makingtwo system calls instead of one. Second, you cannot rely on the fact that file descriptor 0is truly in use. If it was closed without your knowledge (say, before a fork and exec)then dup will duplicate onto the wrong file descriptor.

3a8082e126
Reply all
Reply to author
Forward
0 new messages