Reputation: 2299
I'm supposed to write a simple custom shell in C that can handle redirection with just the "<" and ">" commands.
To do this I'm parsing each command (in an array of strings), checking for the characters '<' and '>' and then opening a file name with open(fd, filename, flags)
to either read or write to.
If I issue these commands (where % signifies my shell), I expect to get the output below:
% echo hello > output.txt
% cat output.txt
hello
However, when I issue these commands, and really any commands, it seems to ignore (but not ignore?) my redirections. This is what happens when I issue the same commands:
% echo hello > output.txt
% cat output.txt
hello > output.txt
The weird part is, it does create a file, called "output.txt", and writes to it, "hello > output.txt"
This happens with both the input and output redirectors. Here is just the code for opening and executing an output command.
int fd;
open_write_file(&fd, commands[index]);
dup2(fd, 1);
execvpe(commands[0], commands, envp);
close(fd);
Note that open_write_file()
opens the file name, with flags O_WRONLY | O_TRUNC | O_CREAT, S_RUSR | S_IRGRP | S_IWGRP | S_IWUSR
and does error checking to ensure it opens correctly. How can I solve this and get it to actually execute the real command I want?
Upvotes: 1
Views: 8252
Reputation: 12619
The syntax of open
is fd = open(path, flags, [mode]);
In case of >
, you'd better use the fd = creat(path, mode);
syscall, which overwrites and creates by default.
When you parse, the argv array for execvpe
should include the parameters up to, but not including, the 1st redirection symbol >
or <
. The argv array shall have a last NULL-pointer element to indicate its end.
The redirections should happen after a fork()
syscall in the child process, otherwise your shell loses its stadard IO and the exec
will wipe it out completely.
/* Parse input line, create argv array, and inputfile/outputfile names */
...
if (fork() == 0) {
/* Child process: stdin redirection */
fd_in = open(inputfile, O_RDONLY);
close(0);
dup(fd_in);
close(fd_in);
/* Child process: stdout redirection */
fd_out = creat(outputfile, 0644);
close(1);
dup(fd_out);
close(fd_out);
/* Child process: exec other program */
execvp(argv[0], argv); /* Does NOT return */
} else {
/* Parent process: wait until child process exits */
wait();
}
There is a general misunderstanding about what the exec
syscall family does. They simply throw away the current program and replace it with another one in the CURRENT PROCESS. They do not return, as there is nowhere to return to.
What people usually mean, can be done with the fork
exec
wait
syscalls, see above.
Upvotes: 2