call to write() fails unknown reason - c

I open a file with open(), I checked my file descriptor and seems to be ok (3).
But when I try to write on this fd, write() returns -1.
I also print my string, which is shown correctly.
errno = 9, "Bad file descriptor"

I checked my file descriptor and seems to be ok (3)
Your file descriptor is apparently not open for writing. From the documentation for write:
EBADF
fd is not a valid file descriptor or is not open for writing.

I would use the functions given in the standard library stdio.h. Use fopen() to open the file, fprintf() to write to a file, and fclose() to close the file. Example:
FILE *fh;
fh = fopen("test.txt","w");
fprintf(fh, "Hello World!\n");
fclose(fh);
I would bookmark this site as it's an invaluable resource for standard C programming (hint: please check there first ;)
http://www.acm.uiuc.edu/webmonkeys/book/c_guide/

Related

Can I close a FILE without closing the fd?

I've opened a FILE *f with fdopen(fd, "w+") and I would like to keep the fd open after closing with fclose(f).
Is there an elegant way to do that?
Can I simply call fflush(f); free(f); or is that dangerous?
Or is there a way to change the internal fd to an invalid value -1 so that fd cannot be closed by fclose()?
If you want to get the file descriptor and disassociate it from the the FILE*, there is one supported way:
Get the file descriptor with fileno(). (POSIX)
Duplicate it using dup(). (POSIX)
Close the FILE the normal way with fclose(). (c)
Now you only have a file descriptor.
If you'd really like to use a FILE object rather than a file descriptor, you needn't worry about close()ing the file descriptor: fclose() does this for you. Also, if performance is important, you should worry about all of the fdopen() and wrapped system calls defined in f*() standard I/O functions. Big thanks to all the comments!
Also see the fclose man page:
The fclose() function flushes the stream pointed to by fp (writing any buffered output data using fflush(3)) and closes the underlying file descriptor.

Redirecting stdout to socket

I am trying to redirect stdout to a socket. I do something like this:
dup2(new_fd, STDOUT_FILENO);
After doing so all stdio functions writing to the stdout fail. I have tried to reopen stdout this way:
fclose(stdout);
stdout = fdopen(STDOUT_FILENO, "wb");
But printf and other functions still don't work.
EDIT:
I am affraid that I misunderstood the problem at the first place. After some more debugging I've figured out that this is a real issue:
printf("Test"); // We get Broken pipe here
// Reconnect new_fd
dup2(new_fd, STDERR_FILENO);
printf("Test"); // This also returns Broken pipe despite that stdout is fine now
Thanks.
1: on dup2(src, dst)
A number of operating systems track open files through the use of file descriptors. dup2 internally duplicates a file descriptor from the src to dst, closing dst if its already open.
What your first statement is doing is making every write to STDOUT_FILENO to go to the object represented by new_fd. I say object because it could be a socket as well as a file.
I don't see anything wrong with your first line of code, but I don't know how new_fd is defined.
2: on reopening stdout
When you close a file descriptor, the OS removes it from its table. However, when you open a file descriptor, the OS sets the smallest available file descriptor as the returned value. Thus, to reopen stdout, all you need to do is reopen the device. I believe the device changes depending on the OS. For example, on my Mac the device is /dev/tty.
Therefore, to reopen the stdout, you want to do the following:
close(1);
open("/dev/tty", O_WRONLY);
I've solved the problem by clearing a stdio's error indicator after fixing stdout:
clearerr(stdout);
Thanks for your help.

Reopen a file descriptor with another access?

Assume the OS is linux. Suppose I opened a file for write and get a file descriptor fdw. Is it possible to get another file descriptor fdr, with read-only access to the file without calling open again? The reason I don't want to call open is the underlying file may have been moved or even unlinked in the file system by other processes, so re-use the same file name is not reliable against such actions. So my question is: is there anyway to open a file descriptor with different access right if given only a file descriptor? dup or dup2 doesn't change the access right, I think.
Yes! The trick is to access the deleted file via /proc/self/fd/n. It’s a linux-only trick, as far as I know.
Run this program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
FILE* out_file;
FILE* in_file;
char* dev_fd_path;
char buffer[128];
/* Write “hi!” to test.txt */
out_file = fopen("test.txt", "w");
fputs("hi!\n", out_file);
fflush(out_file);
/* Delete the file */
unlink("test.txt");
/* Verify that the file is gone */
system("ls test.txt");
/* Reopen the filehandle in read-mode from /proc */
asprintf(&dev_fd_path, "/proc/self/fd/%d", fileno(out_file));
in_file = fopen(dev_fd_path, "r");
if (!in_file) {
perror("in_file is NULL");
exit(1);
}
printf("%s", fgets(buffer, sizeof(buffer), in_file));
return 0;
}
It writes some text to a file, deletes it, but keeps the file descriptor open and and then reopens it via a different route. Files aren’t actually deleted until the last process holding the last file descriptor closes it, and until then, you can get at the file contents via /proc.
Thanks to my old boss Anatoly for teaching me this trick when I deleted some important files that were fortunately still being appended to by another process!
No, the fcntl call will not let you set the read/write bits on an open file descriptor and the only way to get a new file descriptor from an existing one is by using the duplicate functionality. The calls to dup/dup2/dup3 (and fcntl) do not allow you to change the file access mode.
NOTE: this is true for Linux, but not true for other Unixes in general. In HP-UX, for example, [see (1) and (2)] you are able to change the read/write bits with fcntl using F_SETFL on an open file descriptor. Since file descriptors created by dup share the same status flags, however, changing the access mode for one will necessarily change it for the other.

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>.

Does every process have its stdin stdout stderr defined as Keyboard, Terminal etc?

Does every process have stdin, stdout and stderr associated to it to the Keyboard and Terminal?
I have a small program. I want to replace the keyboard input to a file called new.txt. How do I go about it?
FILE *file1
fopen("new.txt", "r")
close(0); // close the stdio
dup2(file1, 0);
Would this work? Now my stdio is redirected to the FILE?
No, not every process. But on operating systems that give you a command-line window to type in, a program started from that command line will have stdin connected to the keyboard, and stdout and stderr both going to the terminal.
If one program starts another, then often the second program's standard streams are connected to the first program in some way; for example, the first program may have an open descriptor through which it can send text and pretend that it's the "keyboard" for the second process. The details vary by operating system, of course.
In response to your question:
Would this work ?
No. dup2() takes two file descriptors (ints) while you're passing it a FILE * and an int. You can't mix file handles (FILE *s) and file descriptors (ints) like that.
You could use open instead of fopen to open your file as a file descriptor instead of a file handle, or you could use fileno to get the file descriptor from a file handle. Or you could use freopen to reopen the stdin file handle to a new file.
Note that file descriptors (ints) are part of POSIX operating systems and are only portable to other POSIX systems, while file handles (FILE *s) are part of the C standard and are portable everywhere. If you use file descriptors, you'll have to rewrite your code to make it work on Windows.

Resources