Selection output file using dup() - c

So I'm trying to redirect standard output to a file using dup().
int save_fd;
save_fd=dup(1); //saves the current stdout
close(1); //closes stdout
dup2(file.txt, 1);//redirect output to file.txt
//output goes to file.txt
dup2(save_fd, 1); restore stdout
close(1);
I know I can open a file using fopen. Since dup2 takes int, how do I specify the file descriptor for file.txt?

Use open which returns an fd instead of fopen.

Well, you have two possibilities to get a file descriptor:
open()
fopen() and then call fileno() on the opened stream
So, in the case of open() the return value in case of success is the file descriptor you're looking for:
int fd = open("some_path", ...);
while in the case you want to use fopen(), you can still retrieve the file descriptor associated with the open stream but you need to call the function fileno():
FILE *stream = fopen(some_file, "w");
int fd = fileno(stream);

Related

fstat st_size says file size is 0 when unlinking file

Somewhere online I've seen a technique to immediately unlink a temporary file after opening it, since you will discard it anyway. As per my understanding of the man-page for unlink, the file will not be unlinked as long as it has an open file descriptor.
When I execute the following piece of code:
char *file, *command;
asprintf(&file, "/tmp/tempXXXXXX");
int fd = mkstemp(file);
unlink(file);
asprintf(&command, "some_command > %s", file); /*Writes n bytes in temp file*/
FILE *f = popen(command, "re");
pclose(f);
struct stat sbuf;
fstat(fd, &sbuf);
printf("%i\n", sbuf.st_size);
close(fd);
free(file);
free(command);
exit(0);
It will print a size of 0. However, if I comment unlink(file), it will show the correct file size. I would expect both scenarios to show the correct size of the file, since unlink should wait till no processes have the file open anymore. What am I missing here?
You're missing the fact that the file referred to by your fd is not the same file as that created by your call to popen().
In a POSIX-like shell, some_command > some_file will create some_file if it does not already exist, otherwise it will truncate some_file.
Your call to popen() invokes a shell, which in turn creates or truncates the output file before invoking some_command as per POSIX.
Since you have unlinked some_file before the call to popen(), the file is created anew: that is, the output file set up by your popen() shell is allocated under a different inode than the (now anonymous) file created by your previous call to mkstemp().
You can see that the files are different if you compare st_ino values from your fstat() (by fd) and a separate call to stat() (by name) after the popen().

How read remember the last offset of file?

How read function know the next position to read from a file.
or How can I manage to made a function that can remember last offset of file even after open another file a changing it's file descriptor.
Is there is a way to know that a file descriptor is already opened and pointed to a file?
like this:
int main()
{
int fd;
char *file;
file = (char *)malloc(sizeof(char) * 32);
fd = open("file.txt", O_RDONLY);
read_file(fd, *file); /* reading the first line from file.txt */
fd = open("file1.txt", O_RDONLY);
read_file(fd, *file); /* reading the first line from file1.txt */
fd = open("file.txt", O_RDONLY);
read_file(fd, *file); /* Now it should read the second line from file file.txt, how can I manage to do that*/
close(fd);
return (0);
}
The current location in the file is maintained by the kernel I think, the file descriptor serves as the key to all the information associated with the open file.
If you need to open and read from two files at the same time, they should of course not share the file descriptor. Just use two, one per file.
const int fd1 = open("file.txt", O_RDONLY);
const int fd2 = open("file1.txt", O_RDONLY);
The treatment of char *file in your code makes no sense, but at this point you can mix accesses to fd1 and fd2.
Remember to close the files when you're done:
close(fd2);
close(fd1);
In real code you would also check that the open-calls succeeded, before trying to do I/O from the file(s), of course.
Is there a way to know that a file descriptor is already opened and
pointed to a file?
If you can lseek(fd, 0, SEEK_CUR) successfully, that means that fd is opened and seekable (so probably a file, but remember that "file" includes directories and device files as well as regular files).
If it returns (off_t)-1 and errno==EBADF then the descriptor is not open; if returns (off_t)-1 and errno==ESPIPE, then it's a pipe, socket, or FIFO.

read file using file descriptor

I need to read a file opened like this:
int outfile = open(*fileName, "w");
using the file descriptor, I'm doing that like this:
char txt[50];
int bytes;
bytes = read(outfile,txt, 50);
But I'm getting segmentation fault and the application abort, any ideas?
Note the second argument to open. It's "w" this seems like it should indicate that you're opening the file for writing. However, my man pages for open indicates that the second argument should be one of: O_RDONLY, O_WRONLY, or O_RDWR. (fopen uses strings like "w", "w+", "r", ... but that's fopen not open). You may be getting lucky that the value of "w" as an int sets you up for writing but you really want to check your return values and probably want to use
open(*filename, O_RDWR);
to set up the mode for reading and writing.

get address of Linux file descriptor

There is fileno to get the file descriptor of a FILE*.
How do you get the address for the FILE* given a file descriptor number, e.g. as returned from pipe?
fileno
pipe
You want to use the fdopen() function:
FILE * file = fdopen(fd, "r");
so you could use it in combination with pipe like this:
FILE * file = fdopen(pipe(..,..), "r");

Can someone explain what dup() in C does?

I know that dup, dup2, dup3 "create a copy of the file descriptor oldfd"(from man pages). However I can't digest it.
As I know file descriptors are just numbers to keep track of file locations and their direction(input/output). Wouldn't it be easier to just
fd=fd2;
Whenever we want to duplicate a file descriptor?
And something else..
dup() uses the lowest-numbered unused descriptor for the new descriptor.
Does that mean that it can also take as value stdin, stdout or stderr if we assume that we have close()-ed one of those?
Just wanted to respond to myself on the second question after experimenting a bit.
The answer is YES. A file descriptor that you make can take a value 0, 1, 2 if stdin, stdout or stderr are closed.
Example:
close(1); //closing stdout
newfd=dup(1); //newfd takes value of least available fd number
Where this happens to file descriptors:
0 stdin .--------------. 0 stdin .--------------. 0 stdin
1 stdout =| close(1) :=> 2 stderr =| newfd=dup(1) :=> 1 newfd
2 stderr '--------------' '--------------' 2 stderr
A file descriptor is a bit more than a number. It also carries various semi-hidden state with it (whether it's open or not, to which file description it refers, and also some flags). dup duplicates this information, so you can e.g. close the two descriptors independently. fd=fd2 does not.
Let's say you're writing a shell program and you want to redirect stdin and stdout in a program you want to run. It could look something like this:
fdin = open(infile, O_RDONLY);
fdout = open(outfile, O_WRONLY);
// Check for errors, send messages to stdout.
...
int pid = fork(0);
if(pid == 0) {
close(0);
dup(fdin);
close(fdin);
close(1);
dup(fdout);
close(fdout);
execvp(program, argv);
}
// Parent process cleans up, maybe waits for child.
...
dup2() is a little more convenient way to do it the close() dup() can be replaced by:
dup2(fdin, 0);
dup2(fdout, 1);
The reason why you want to do this is that you want to report errors to stdout (or stderr) so you can't just close them and open a new file in the child process. Secondly, it would be a waste to do the fork if either open() call returned an error.
The single most important thing about dup() is it returns the smallest integer available for a new file descriptor. That's the basis of redirection:
int fd_redirect_to = open("file", O_CREAT);
close(1); /* stdout */
int fd_to_redirect = dup(fd_redirect_to); /* magically returns 1: stdout */
close(fd_redirect_to); /* we don't need this */
After this anything written to file descriptor 1 (stdout), magically goes into "file".
Example:
close(1); //closing stdout
newfd=dup(1); //newfd takes value of least available fd number
Where this happens to file descriptors:
0 stdin .--------------. 0 stdin .--------------. 0 stdin
1 stdout =| close(1) :=> 2 stderr =| newfd=dup(1) :=> 1 newfd
2 stderr '--------------' '--------------' 2 stderr
A question arose again: How can I dup() a file descriptor that I already closed?
I doubt that you conducted the above experiment with the shown result, because that would not be standard-conforming - cf. dup:
The dup() function shall fail if:
[EBADF]
The fildes argument is not a valid open file descriptor.
So, after the shown code sequence, newfd must be not 1, but rather -1, and errno EBADF.
see this page, stdout can be aliased as dup(1)...
Just a tip about "duplicating standard output".
On some Unix Systems (but not GNU/Linux)
fd = open("/dev/fd/1", O_WRONLY);
it is equivalent to:
fd = dup(1);
dup() and dup2() system call
•The dup() system call duplicates an open file descriptor and returns the new file
descriptor.
•The new file descriptor has the following properties in common with
the original
file descriptor:
1. refers to the same open file or pipe.
2. has the same file pointer -- that is, both file descriptors share one file pointer.
3. has the same access mode, whether read, write, or read and write.
• dup() is guaranteed to return a file descriptor with the lowest integer value available.It is because of this feature of returning the lowest unused file descriptor available that processes accomplish I/O redirection.
int dup(file_descriptor)
int dup2(file_descriptor1, file_descriptor2)

Resources