I saw this code snippet from APUE
dup2(fd,0);
dup2(fd,1);
dup2(fd, 2);
if (fd > 2)
close(fd);
In my understanding, it makes stdin, stdout and stderr all point to fd. It says that lots program contain this code, why? What's it functionality?
I'm going to add to the comments and answer here because even though they're correct, I would still have a hard time understanding exactly when and why this sequence of calls were needed.
This sequence of function calls is typically used when a process will run as a daemon. In that case, among other things, the daemon doesn't want to have the standard I/O file descriptors attached to the terminal (or other resources). To 'detach' those descriptors, something like the following might occur:
int fd;
fd = open("/dev/null",O_RDWR); // missing from APUE exercise 3.4 example
if (fd != -1)
{
dup2 (fd, 0); // stdin
dup2 (fd, 1); // stdout
dup2 (fd, 2); // stderr
if (fd > 2) close (fd);
}
What this does is bind /dev/null' to each of the standard I/O descriptors and closes the temporary descriptor used to open/dev/null` in the first place (as long as that open didn't end up using one of the descriptors usually used for the standard I/O descriptors for some reason).
Now the daemon has valid stdin/stdout/stderr descriptors, but they aren't referring to a file or device that might interfere with another process.
This is mostly used in daemon programs because the daemon not connected with the terminal or tty. so for that we need maintain the error or printed statements in one file. for that only we were using this statements. In our system File descriptor 0,1,2 is already allocated for the standard buffers like stdin,etc...
Dup2 function is something different from dup function.
In dup2 function we no need to close already using file descriptor.
In this dup2 function itself if the second argument file descriptors is already using means
without close() function dup2 is closed the second argument fd and allocated a dup of first argument fd.
Then first argument fd is connected to second fd and do the first fd works
For example dup2(fd,1) means the file descriptor works are copied to the stdout.
fd is contains any the statements is print the stdout.
Related
Say I have the following code:
close(1);
int fd = open("temp.txt", O_WRONLY | O_CREAT);
if (fork() == 0)
printf("Message from A\n");
printf("Message from B\n");
I am aware that stdout is line-buffered, and I've noticed that, at least on my system, this works as one would expect.
i.e.
The contents of temp.txt are:
Message from B
Message from A
Message from B
However, what is the behavior defined by POSIX for the above code? Is line-buffering preserved for file descriptor 1 (even after a close())? Is it undefined? Something else? I am assuming that the open() command will always use file descriptor 1 for temp.txt in the above code.
Additionally, would it be possible, say, for only part of "Message from A\n" or "Message from B\n" to be written to the buffer associated with file descriptor 1 before the CPU loaded the other process and overwrote the partial message that was just written?
e.g.
Is it possible that the parent parent process only manages to write "Message" to the buffer before it gets interrupted by the child, resulting in the following content in temp.txt (or something similar):
Message from A
from B
Message from B
NOTE:
The code above is what was given to me in an assignment I have for one of my classes. I understand that it is better to open a file and then call dup2(), rather than closing file descriptor 1, and then opening the file.
If standard output is terminal, it is line buffered. If its a file, it does not need to be. It depends on platform/implementation.
In your second example program, you are not seeing 1000 lines because you are terminating child processes with _exit.
if (pid == 0)
{
_exit(0);
}
Instead you should be using exit. The difference is exit does stuff such as closing files and flushing streams, then calls _exit to perform actual termination. If you terminate child processes with regular exit (or just let them terminate at the end of main regularly), their output should be flushed into file as well.
Update: Accordingly, whether _exit flushes streams or not is implementation defined, this is probably the reason Barmar encountered different results with Mac and Linux, but exit always flushes. Quote from the _exit link:
Whether open streams are closed (without flushing) is
implementation-defined
POSIX doesn't specify C's buffering, it's specified by the C standard.
The default buffering of a the standard input and output streams is determined when the program starts. Changing the FD associated with the stream has no effect on this. If stdout was initially associated with a terminal, it will be line-buffered, and opening a file on FD 1 doesn't change this, so it's still line-buffered when writing to the file.
After ignoring SIGPIPE with a call to signal(), there is a possibility that a write() call will fail with errno set equal to EPIPE. Do I still have to close the file descriptor like in the example below?
if (write(sock_fd, buf, len) < 0) {
if (errno == EPIPE) {
close(sock_fd);
}
}
Remember that when you create a pipe, using the system call of the same name, you get two file descriptors: one for reading and one for writing. You get EPIPE from a write operation, on the write fd, when the read fd has been closed. The write fd is still open. If you try to write to it again, you'll get EPIPE again.
(Often, when this happens, the pipe was set up by a shell or some other parent process, and the read fd was never available to your program, but that doesn't matter to the kernel. It was open in some process(es) and now it isn't.)
Since it's still open, you do need to close it. However, exiting automatically closes all fds that are still open. So if the very next thing you'd do after closing the pipe is to exit, then you don't need to bother closing it first. Since it is a pipe, and you already got EPIPE, there can't be any delayed write errors that close might report.
You always have to close file descriptors. No ifs, no buts.
I've been wanting to create a child process that forks off twice to create two child processes. With the output of one, sent to the other.
I found this example code. But I'm confused as to how it works.
I found an example here. But I'm confused by the way dup is used and how it works.
i.e.
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
Output is then piped into a second forked process and it's pipes are connected like this:
close(0);
dup(fd[0]);
close(fd[0]);
close(fd[1]);
The main relevant lines are these — they form a standard idiom (but it is easier to replace the first two lines with dup2(fd[1], 1)):
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
The dup() function duplicates its argument file descriptor to the lowest-numbered unopen file descriptor. The close() closes descriptor 1, and descriptor 0 is still open, so the dup() makes standard output 1 refer to the write side of the pipe fd[1]. The other two close calls correctly close both ends of the pipe. The process shouldn't be reading from the read end of the pipe fd[0] and standard output is writing to the write end of the pipe so the other descriptor isn't needed any more (and could lead to problems if it was not closed).
So, this is a standard sequence for connecting the write end of a pipe to the standard output of a process. The second sequence is similar, but connects the read end of the pipe to standard input (instead of the write end to standard output).
Generally, when you connect one end of a pipe to either standard input or standard output, the process should close both ends of the original pipe.
I note that there was no error checking, though it is unlikely that anything would go wrong — unless the process had been started with either standard output or standard input closed, contrary to all reasonable expectations.
I'm playing around with the dup2() function to try and get a better grasp of it.
From looking at the manual, it takes two parameters. First is the existing file descriptor and second parameter is the copied file descriptor.
I decided to try and redirect stdout to my write end of the pipe.
Judging by the manual I thought the code should be...
if ((dup2(STDOUT_FILENO, fd[1])) <= 0)
{
printf("error on dup \n");
}
write(STDOUT_FILENO, "Hi \n", 5);
As stdout would now be duplicated to fd[1]. Therefore if we wrote to stdout we should be writing to write end of pipe. However this still prints to screen. So I assumed it should be fd[1] followed by stdout. So does that mean stdout is now a copy of fd[1] and that's why it's working.
Lastly if I wanted to write back to screen....how would I do this in same process?
The prototype for dup2 is: int dup2(int oldfd, int newfd);
So your cope:
dup2(STDOUT_FILENO, fd[1])
copies the stream associated with STDOUT_FILENO (which normally will be 1) to the decriptor in fd[1]. Let's assume you have put the descriptor value 4 in fd[1], then at the end, both 1 and 4 will both point to the "standard output stream" which is usually the terminal tty/pty.
After the call (if successful), fd[1] no longer refers to a pipe. Sounds like you are confusing dup/dup2 functionality with pipe. pipe() creates a descriptor pair with a read and write end. If you then fork, you can connect two processes with the pipe, and after that, a child process with a pipe can dup its pipe to STDIN_FILENO or STDOUT_FILENO such that standard library routines will read/write from those descriptors thinking they are reading/writing to the terminal.
The only thing that makes 0, 1, 2 special are that they are initially opened to a terminal, and that library routines refer to them by number (or macro SDTIN_FILENO, etc.) The dup calls basically increment the reference count for a particular descriptor and link the underlying descriptor slot to the original slot.
Sounds like what you want to do is pass fd[1] in the first argument, and dup it to STDOUT_FILENO in order to connect your pipe to a standard stream.
When we use dup to redirect STDOUT to a pipe we do:
close(1); dup(fd[1]);
close(fd[0]);
close(fd[1]);
execlp("ls","-al",(char *) NULL);
but we are closing both ends end of the pipe. then how the STDOUT can be written to the pipe?
You're not closing both ends of the pipe, in the example code. You're closing fd[0] and fd[1]. Initially, closing those would have been enough to close both ends of the pipe, but it's not after you duplicated fd[0]. You'd have to close the duplicated fd also to close all your references to the pipe. That would be silly though: you're keeping an end open precisely so that ls can write to.
Perhaps your confusion is about close() is closing? It closes the fd, the reference to one of the ends of the pipe. It doesn't close the pipe itself: that's what shutdown() would do. (If you don't call shutdown, the pipe is automatically closed when every fd referring to it has been closed.) So, because the duplicated fd is still open, the process can write to the pipe (which isn't closed, because only two of the three references to it were closed).
Because once the file descriptor number 1 (e.g. standard out) is closed, that number is available for further dup or open calls.
You should check the result of your close and dup syscalls.
Of course closing both ends of a pipe is non-sense, unless you do something useful before (i.e. reading or writing on appropriate ends).
See open(2), dup(2), pipe(2), close(2) man pages. Read the Advanced Linux Programming book.