Reputation: 56
I am making my own shell in c and i am now trying to make a function which redirects the standard error of the shell to a specific file, an option which manages to show where the standard error is currently going to and anotherone able to reset the stderr to what it was originally.
I have implemented this code to redirect the stderr:
int fd, new_fd;
if((fd = open(tokens[1], O_RDWR)) == -1){
perror("Error opening: ");
return 0;
}
if(dup2(fd, STDERR_FILENO) == -1){
perror("Error: ");
}
if(close(fd) == -1){
perror("Error closing: ");
}
Now, I cant find anything for the option to restore or to show where the stderr is going to now, if someone could help me achieving this it would be amazing!
if(tokens[1] == NULL){
//Shows where the standard error is currently going to
return 0;
}
if(strcmp(tokens[1], "-reset") == 0){
//Restores the standard error to what it was originally
return 0;
}
Upvotes: 0
Views: 529
Reputation: 132969
To restore stderr
, save the original one to a new file descriptor using dup
before replacing it. If you like you can later on restore it from that backup. If you don't do that and just replace it with the file you've opened, it will be lost as dup2
closes the descriptor it replaces and that way the only descriptor left for the old stderr
was lost.
int backup = dup(STDERR_FILENO);
// ... later
dup2(backup, STDERR_FILENO);
Getting the name of a file descriptor is generally not possible for the sole reason that this is not a one-to-one mapping. If a file descriptor refers to a file, which is not guaranteed to begin with (it could be a socket, a pipe, a shared memory object, etc.), this file may exist multiple time with different names within a single or even multiple different directories; just hard-link the file using ln
without -s
and you have two file names both pointing to the same file.
Maybe the following mental image makes it clearer: Imagine that a file is a piece of disk storage referenced by a number. Directory entries are just lookup tables that map a name to a file number and of course, multiple names may map to the same file number. If you open a file using a name, the name is only used once to lookup its number, the actual access happens using that number. After the file has been opened, the file descriptor you get is only linked to the file itself and therefor all it requires is the file number. The file name may even change even while you are writing to the file as all that changes here is the mapping reference.
You can use fstat
on a file descriptor to get a struct stat
description of the file it references, that is, in case it does reference a file, but as you may notice, this struct contains no name. It only contains the file number (st_ino
).
On BSD systems, including macOS, you can call fcntl
with the command F_GETPATH
and you get the path used for opening; the system simple remembers that path somewhere.
On Linux this option does not exist. The only option you have is calling readlink
on the /proc/self/fd/X
where X
is the file descriptor number. This will also give you the path of the file used for opening.
Keep in mind so, this is not guaranteed to be the only name for that file and the moment you make that call, the file name may have already changed or the file may not even exist anymore as if an open file is deleted, only the directory entry is deleted at once but the file itself keeps existing as long as there is still at least one active file descriptor referring to it; once the last descriptor closed, the file itself is deleted (which means the space it consumed it added back to the free pool of the disk and may be reused by other files).
Upvotes: 2