Should I close file descriptor passed to fchdir? - c

When I want to change directory using a file descriptor, should I close the directory FD after calling fchdir, or the fchdir closes the FD automatically?
int fd = open(…);
if (fd == -1) error();
fchdir(fd);
//close(fd);

IMHO, if the code is done with fd to never use it again, call close.
The call to fchdir will not close the file descriptor (see the posix description of fchdir
).
fchdir likely (depends on OS and file system) obtains the needed information from fd before returning to the caller. Here is an example of how one specific OS file system handles system calls for fchdir
For a more informed decision whether you should or should not close fd investigate the description of close:
The close() function shall deallocate the file descriptor indicated by fildes. To deallocate means to make the file descriptor available for return by subsequent calls to open() or other functions that allocate file descriptors. All outstanding record locks owned by the process on the file associated with the file descriptor shall be removed (that is, unlocked).

Related

open(2) a file from existing descriptor

Background
I have multiple threads in the same process that are all installing fcntl(2) locks on a given file. These locks must block, thus to achieve intra-process blocking I must use Open file description locks (or OFD locks, see fcntl(2)). And it is documented that:
Open file description locks placed via the same open file
description (i.e., via the same file descriptor, or via a
duplicate of the file descriptor created by fork(2), dup(2),
fcntl() F_DUPFD, and so on) are always compatible: if a new lock
is placed on an already locked region, then the existing lock is
converted to the new lock type. (Such conversions may result in
splitting, shrinking, or coalescing with an existing lock as
discussed above.)
On the other hand, open file description locks may conflict with
each other when they are acquired via different open file
descriptions. Thus, the threads in a multithreaded program can
use open file description locks to synchronize access to a file
region by having each thread perform its own open(2) on the file
and applying locks via the resulting file descriptor.
Thus, when a thread is booting up, it must open its own descriptor via open. It should be noted that the "main thread" has the file already open and threads come and go throughout the processes lifetime.
Question
So I was thinking, is there any way I can re-use an existing file descriptor to open a separate descriptor to the same file without dup(2)?
In otherwords, if I had file descriptor A, but do not know the filename, can I open descriptor B pointing to that same file A is?
My first instinct is as follows, whereas fd is the original file descriptor and fd2 is the "deep cloned" descriptor.
char buff[500]
sprintf(buff, "/proc/%d/fd/%d", getpid(), fd);
fd2 = open(buff, O_RDWR)
However, it feels dirty. I was hoping there is a system call to do this.

Close file in C

Under Linux I use this code to redirect stdout and stderr on a file, as shown in the code the file is opened using fopen(f) and is it closed using close(fd).
int fd;
FILE *f;
f = fopen("test.txt", "rb+");
fd = fileno(f);
dup2(fd,STDOUT_FILENO);
dup2(fd,STDERR_FILENO);
close(fd);
My question is whether the close(fd) statement closes all file descriptors, or is it necessary to use fclose(f) as well ?
The rule is to close the outermost level. Here the FILE object pointed to by f contains the fd file handle but also internal data like a possible buffer and various pointers to it.
When you use close(fd), you free the kernel structures related to the file, but all the data structures provided by the standard library are not released. On the other hand, fclose(f) will internally close the fd file handle, but it will also release all the resources that were allocated by fopen.
TL/DR: if you use fd= open(...); to open a file, you should use close(fd); to close it, but if you use f = fopen(...);, then you should use fclose(f);.
As already pointed out in the other answers, you should use fclose(f); instead of close(fd);.
My question is whether the close(fd) statement closes all file descriptors [...]
No, it won't close all file descriptors. The file descriptors STDOUT_FILENO and STDERR_FILENO will still remain open and will now refer to the opened file test.txt. However, these file descriptors should probably not be closed, as it is good programming practice for STDOUT_FILENO and STDERR_FILENO to remain valid until the end of the program. They will be automatically closed by the kernel on process termination.
C FILE* streams use buffered I/O internally. fclose() flushes this buffer and then closes the file descriptor at OS level. close()'ing a FILE* stream may not flush this internal buffer and you may lose data. So for C streams always use C fxxx() functions.

Why make stdin, stdout and stderr to a single fd?

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.

Memory Mapping a file in POSIX

When memory mapping files in a POSIX system, do we need to keep the file-descriptor open till we're done with the mmaped memory block (and close it after we munmap) or can (should?) we close the file descriptor once mmap succeeds? Both seem to work on my Linux system.
From the Open Group standard
The mmap() function shall add an extra
reference to the file associated with
the file descriptor fildes which is
not removed by a subsequent close() on
that file descriptor. This reference
shall be removed when there are no
more mappings to the file.

Close a FILE pointer without closing the underlying file descriptor

By using fdopen(), fileno() it's possible to open streams with existing file descriptors. However the proper way to close a file, once you've opened it with a stream is to fclose() the FILE pointer. How can one close the stream, but retain the open file descriptor?
This behaviour is akin to calling fflush() and then fileno(), and then never using the FILE pointer again, except in closing. An additional concern is that if you then fdopen() again, there are now multiple FILE pointers, and you can only close one of them.
If you're on a POSIXy system (which I assume you are, since you have fileno()), you can use dup() to clone the file descriptor:
int newfd = dup(fileno(stream));
fclose(stream);
Or you can hand fdopen() a duplicate file descriptor:
FILE *stream = fdopen(dup(fd), "r");
Either way, the other copy of the fd won't close with the FILE *. However, keep in mind the location pointer is shared, so be careful if you are using both at the same time. Also, any fcntl() locks held on the original fd will be released when you close the copy.
If everything else fails, dup(2) could help.

Resources