read and write to the closed file descriptors [duplicate] - c

I have a question regarding file descriptors in Unix and C programming.
Let's say I use pipe(fd) to get file descriptor 3 and 4 for the pipe ends, 3 connects to the read end and 4 to the write end.
Now I use dup2(fd[write_end],1) to copy the descriptor of the write end (which was 4) to file descriptor 1 in my process. If I now do close(fd[write_end]) will it close descriptor 1 or descriptor 4?

After a successful call to dup2, both file descriptors are valid.
When you then call close(fd[write_end]), because fd[write_end] is set to 4 this is the same as close(4). So file descriptor 1 remains open and usable.

Related

Closing and reopening piped file descriptors for writing in c

I have a question please regarding what happens if I closed a file descriptor after writing into it ( e.g fd[1] after piping fd ), then opened it again to write. Will the data be overwritten and all the previous ones will be gone or it will keep on writing from the end point it stopped at after the first write?
I used the system call open() with the file descriptor and no other arguments.
If you close either of the file descriptors for a pipe, it can never be reopened. There is no name by which to reopen it. Even with /dev/fd file systems, once you close the file descriptor, the corresponding entry in the file system is removed — you're snookered.
Don't close a pipe if you might need to use it again.
Consider whether to make a duplicate of the pipe before closing; you can then either use the duplicate directly or duplicate the duplicate back to the original (pipe) file descriptor, but that's cheating; you didn't actually close all the references to the pipe's file descriptor. (Note that the process(es) at the other end of the pipe won't get an EOF indication because of the close — there's still an open file descriptor referring to the pipe.)

Redirecting STDIN/OUT/ERR

I'm trying to create a linux daemon in c and found some sample code on this page.
I understand all the code except where it tries to redirect STDIN, STDOUT and STDERR (to /dev/null/). I also found a number of questions on here related to why these should be redirected (which I understand).
Specifically the section of code my question relates to is:
/* Route I/O connections */
/* Open STDIN */
i = open("/dev/null", O_RDWR);
/* STDOUT */
dup(i);
/* STDERR */
dup(i);
Reading the man page for dup() it implies that dup() simply duplicates a file descriptor.
So I don't understand how this does the redirect ? Is the compiler taking hints from the comments in the line above ?, or is it missing some code ?, is it plain wrong ?, or am I missing something ?
It's import to understand the previous bit of the example code you link to:
/* close all descriptors */
for (i = getdtablesize(); i >= 0; --i)
{
close(i);
}
This closes all open file descriptors including STDIN, STDOUT and STDERR.
As the manpage for open() states
The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process
So the subsequent call to open() in the example code will redirect file descriptor 0 which is STDIN, to /dev/null.
The subsequent calls to dup() will duplicate the file descriptor using the next lowest numbers. STDOUT is 1, and STDERR is 2.
The manpage for dup() states:
The dup() system call creates a copy of the file descriptor oldfd, using the lowest-numbered unused descriptor for the new descriptor
From the man page of dup:
The dup(oldfd) system call creates a copy of the file descriptor oldfd,
using the lowest-numbered unused descriptor for the new descriptor.
If you see the referenced code, he is first closing all the open file descriptors:
for (i = getdtablesize(); i >= 0; --i)
{
close(i);
}
After that when you call dup(i), it will copy the file descriptor i to the lowest available descriptor, which will be 0 (stdin). Doing that again will copy it to descriptor 1 (stdout) and similarly for descriptor 2 (stderr). In this way, the stdin, stdout, and stderr of the daemon process are pointing to /dev/null.
Every process gets three open file descriptors which are the stdin, stdout, and stderr (these descriptors usually have the values 0, 1, and 2 respectively). When you call printf(), for example, it writes to the file pointed to by the stdout descriptor. By pointing this descriptor to another file (such as /dev/null), any output from this process will get redirected to that file. Same logic applies for stdin and stderr.
On the shell, when you run something like ls > ls.out, the shell does the same. It fork()s a new process, opens ls.out for writing, and calls dup (or dup2) to copy the file descriptor of ls.out to this process' stdout.

how to check if the file is closed

I have file descriptor and inside my signal handler, i close the file. But due to other conditions, the file could have been closed earlier. Is there a way to check if the file descriptor points to an open file in c and linux?
UPDATE:
Is it possible to determine filename associated with a file descriptor? This way if the fd gets recycled, app can detect it.
Try to do any file operation like lseek on the file descriptor. If it returns -1. Then check errno, if its EBADF then the file descriptor is already closed.
Try to do lseek in an unaffected manner like below.
lseek(fd, 0, SEEK_CUR);
Usually while opening the first file in a program we always get the file descriptor as 3. After this file is closed, if we try to open some other file we will get the same file descriptor as 3. Because always we will get the lowest available number. If we are closing and reopening many files in a program, then we need to improve our code to track of file descriptors list to check whether its closed or not.
When you open a file, it always get the minimal available fd assigned. So if you close your fd, and then open another file somewhere in your code, you could easily have the same fd reassigned to this new file. So there is no reliable way to tell that the file descriptor is closed, because it can now point to another opened file.
After you closed the file descriptor fd assign -1 to it, so you later could test fd against -1 to see if you already closed it.
You could lookup the filename a (valid) file descriptor referrs to by calling readlink() on /proc/<pid>/fd/<file descriptor>.

dup2 / dup - Why would I need to duplicate a file descriptor?

I'm trying to understand the use of dup2 and dup.
From the man page:
DESCRIPTION
dup and dup2 create a copy of the file descriptor oldfd. After successful return of dup or dup2, the old and new descriptors may be used interchangeably. They share locks, file position pointers and flags; for example, if the file position is modified by using lseek on one of the descriptors, the position is also changed for the other.
The two descriptors do not share the close-on-exec flag, however. dup uses the lowest-numbered unused descriptor for the new descriptor.
dup2 makes newfd be the copy of oldfd, closing newfd first if necessary.
RETURN VALUE
dup and dup2 return the new descriptor, or -1 if an error occurred (in which case, errno is set appropriately).
Why would I need that system call? What is the use of duplicating the file descriptor? If I have the file descriptor, why would I want to make a copy of it? I'd appreciate it if you could explain and give me an example where dup2 / dup is needed.
The dup system call duplicates an existing file descriptor, returning a new one that
refers to the same underlying I/O object.
Dup allows shells to implement commands like this:
ls existing-file non-existing-file > tmp1 2>&1
The 2>&1 tells the shell to give the command a file descriptor 2 that is a duplicate of descriptor 1. (i.e stderr & stdout point to same fd).
Now the error message for calling ls on non-existing file and the correct output of ls on existing file show up in tmp1 file.
The following example code runs the program wc with standard input connected
to the read end of a pipe.
int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
close(STDIN); //CHILD CLOSING stdin
dup(p[STDIN]); // copies the fd of read end of pipe into its fd i.e 0 (STDIN)
close(p[STDIN]);
close(p[STDOUT]);
exec("/bin/wc", argv);
} else {
write(p[STDOUT], "hello world\n", 12);
close(p[STDIN]);
close(p[STDOUT]);
}
The child dups the read end onto file descriptor 0, closes the file de
scriptors in p, and execs wc. When wc reads from its standard input, it reads from the
pipe.
This is how pipes are implemented using dup, well that one use of dup now you use pipe to build something else, that's the beauty of system calls,you build one thing after another using tools which are already there , these tool were inturn built using something else so on ..
At the end system calls are the most basic tools you get in kernel
Cheers :)
Another reason for duplicating a file descriptor is using it with fdopen. fclose closes the file descriptor that was passed to fdopen, so if you don't want the original file descriptor to be closed, you have to duplicate it with dup first.
dup is used to be able to redirect the output from a process.
For example, if you want to save the output from a process, you duplicate the output (fd=1), you redirect the duplicated fd to a file, then fork and execute the process, and when the process finishes, you redirect again the saved fd to output.
Some points related to dup/dup2 can be noted please
dup/dup2 - Technically the purpose is to share one File table Entry inside a single process by different handles. ( If we are forking the descriptor is duplicated by default in the child process and the file table entry is also shared).
That means we can have more than one file descriptor having possibly different attributes for one single open file table entry using dup/dup2 function.
(Though seems currently only FD_CLOEXEC flag is the only attribute for a file descriptor).
http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html
dup(fd) is equivalent to fcntl(fd, F_DUPFD, 0);
dup2(fildes, fildes2); is equivalent to
close(fildes2);
fcntl(fildes, F_DUPFD, fildes2);
Differences are (for the last)- Apart from some errno value beteen dup2 and fcntl
close followed by fcntl may raise race conditions since two function calls are involved.
Details can be checked from
http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
An Example of use -
One interesting example while implementing job control in a shell, where the use of dup/dup2 can be seen ..in the link below
http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs

File descriptors in C

Let's suppose that in my OS exists N file descriptors. How many file descriptors will OS have after executing the code below:
int fd = dup(oldfd);
How about :
int fd = dup2(oldfd,newfd);
Thanks!
Its given in man pages. You'll have N+1 file descriptors after calling either one of them.
From manpages
...
dup and dup2 create a copy of the file descriptor oldfd.
After successful return of dup or dup2, the old and new descriptors
may be used interchangeably.
dup uses the lowest-numbered unused descriptor for the new descriptor.
...
So, an unused descriptor is used as a new one. That should answer your question.

Resources