Round 2
After reading some of the answers, my revised code is:
int pid = fork();
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
if (in) { //if '<' char was found in string inputted by user
int fd0 = open(input, O_RDONLY, 0);
dup2(fd0, STDIN_FILENO);
close(fd0);
in = 0;
}
if (out) { //if '>' was found in string inputted by user
int fd1 = creat(output, 0644);
dup2(fd1, STDOUT_FILENO);
close(fd1);
out = 0;
}
execvp(res[0], res);
perror("execvp");
_exit(1);
} else {
waitpid(pid, 0, 0);
free(res);
}
It works, but seems the standard output isn’t being reconnected or something to that effect. Here is execution:
SHELL$ cat > file
hello, world
this is a test
SHELL$ cat < file //no output
SHELL$ ls //no output
‘<‘ and ‘>’ both work, but after they are executed there is no output.
Round 1
I have been working on a relatively simple shell in C for a while now, but I am having trouble implementing input (<) and output (>) redirection. Help me find the issues in the following code:
int fd;
int pid = fork();
int current_out;
if (in) { //if '<' char was found in string inputted by user
fd = open(input, O_RDONLY, 0);
dup2(fd, STDIN_FILENO);
in = 0;
current_out = dup(0);
}
if (out) { //if '>' was found in string inputted by user
fd = creat(output, 0644);
dup2(fd, STDOUT_FILENO);
out = 0;
current_out = dup(1);
}
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
execvp(res[0], res);
perror("execvp");
_exit(1);
} else {
waitpid(pid, 0, 0);
dup2(current_out, 1);
free(res);
}
I may have some unnecessary material in there because I have been trying different things to get it to work. I am not sure what is going wrong.
You have way too many file descriptors open after your redirection. Let’s dissect the two paragraphs:
I’m going to be charitable and ignore the fact that you are ignoring errors. However, you will need to error check your system calls.
In the first paragraph, you open a file and capture the file descriptor (it might well be 3) in the variable
fd. You then duplicate the file descriptor over standard input (STDIN_FILENO). Note, though, that file descriptor 3 is still open. Then you do adup(0)(which, for consistency, should beSTDIN_FILENO), getting another file descriptor, perhaps 4. So you have file descriptors 0, 3 and 4 pointing at the same file (and, indeed, the same open file description — noting that an open file description is different from an open file descriptor). If your intention withcurrent_inwas to preserve the (parent) shell’s standard input, you have to do thatdup()before you do thedup2()that overwrites the output. However, you would be better off not altering the parent shell’s file descriptors; it is less overhead than re-duplicating the file descriptors.Then you more or less repeat the process in the second paragraph, first overwriting the only record of file descriptor 3 being open with the
fd = creat(...)call but obtaining a new descriptor, perhaps 5, then duplicating that over standard output. You then do adup(1), yielding another file descriptor, perhaps 6.So, you have stdin and stdout of the main shell redirected to the files (and no way of reinstating those to the original values). Your first problem, therefore, is that you are doing the redirection before you
fork(); you should be doing it after thefork()— though when you get to piping between processes, you will need to create pipes before forking.Your second problem is that you need to close a plethora of file descriptors, one of which you no longer have a reference for.
So, you might need:
Before you do any of this, you should ensure that you’ve already flushed the shell’s standard I/O channels, probably by using
fflush(0), so that if the forked child writes to standard error because of a problem, there is no extraneous duplicated output.Also note that the various
open()calls should be error-checked.