Alex
Alex

Reputation: 2299

Executing redirection ( ">" and "<" ) in custom shell in C

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

Answers (1)

SzG
SzG

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

Related Questions