Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - Proper way to close files when using both open() and fdopen()

So I'm building a Unix minishell in C, and am implementing input, output, and err redirection, and have come across a problem with files. I open my files in a loop where I find redirection operators, and use open(), which returns an fd. I then assign the child's fd accordingly, and call an execute function.

When my shell is just going out and finding programs, and executing them with execvp(), I don't have much of a problem. The only problem is knowing whether or not I need to call close() on the file descriptors before prompting for the next command line. I'm worried about having an fd leak, but don't exactly understand how it works.

My real problem arises when using builtin commands. I have a builtin command called "read", that takes one argument, an environmental variable name(could be one that doesn't yet exist). Read then prompts for a value, and assigns that value to the variable. Here's an example:

% read TESTVAR
test value test value test value
% echo  ${TESTVAR}
test value test value test value

Well lets say that I try something like this:

% echo here's another test value > f1
% read TESTVAR < f1
% echo  ${TESTVAR}
here's another test value

This works great, keep in mind that read executes inside the parent process, I don't call read with execvp since it's builtin. Read uses gets, which requires a stream variable, not an fd. So after poking around on the irc forums a bit I was told to use fdopen, to get the stream from the file descriptor. So before calling gets, I call:

rdStream = fdopen(inFD, "r");

then call

if(fgets(buffer, envValLen, rdStream) != buffer) 
{
    if(inFD) fclose(rdStream);
    return -1;
}
if(inFD) fclose(rdStream);

As you can see, at the moment I'm closing the stream with fclose(), unless it is equal to stdin(which is 0). Is this necessary? Do I need to close the stream? Or just the file descriptor? Or both? I'm quite confused on which I should close, since they both refer to the same file, in a different manner. At the moment I'm not closing the fd, however I think that I definitely should. I would just like somebody to help make sure my shell isn't leaking any files, as I want it to be able to execute several thousand commands in a single session without leaking memory.

Thanks, if you guys want me to post anymore code just ask.

like image 800
robins35 Avatar asked Dec 03 '12 20:12

robins35


People also ask

How do you close after Fdopen?

If fdopen() returns NULL, use close() to close the file. If fdopen() is successful, you must use fclose() to close the stream and file.

Why it is necessary to close a file during execution of the program in C?

A file needs to be closed after a read or write operation to release the memory allocated by the program. In C, a file is closed using the fclose() function. This returns 0 on success and EOF in the case of a failure.

How do you close a file pointer?

The fclose function takes a file pointer as an argument. The file associated with the file pointer is then closed with the help of fclose function. It returns 0 if close was successful and EOF (end of file) if there is an error has occurred while file closing.

Does Fclose call close?

The fclose() function performs a close() on the file descriptor that is associated with the stream pointed to by stream. After the call to fclose(), any use of stream causes undefined behavior. Upon calling exit(), fclose() is performed automatically for all open files.


1 Answers

The standard says:

The fclose() function shall perform the equivalent of a close() on the file descriptor that is associated with the stream pointed to by stream.

So calling fclose is enough; it will also close the descriptor.

like image 156
cnicutar Avatar answered Oct 07 '22 15:10

cnicutar