6

I've been implementing a small program that executes a given command using execvp(). It works fine when not using redirection, but when I run a command such as:

cat file1.txt > redirected.txt

cat outputs the following error messages and fails:

cat: >: No such file or directory
cat: redirected.txt: No such file or directory

I've done some digging around and I'm starting to think that perhaps execvp() isn't allowed to do redirection because it doesn't run in the shell. Does that mean that I would have to manually pick out when redirection occurs and use pipes in my fork/exec code to get around this restriction? Is there a better way than to use execvp()?

Thanks!

Greg S.
  • 61
  • 1
  • 1
  • 2

3 Answers3

9

Your "small program that executes a given command" is essentially a shell. Since you are writing a shell, it is your job to implement redirections with whatever syntax you desire. The > redirection operator is not a feature of the kernel, it is a shell feature.

To implement sh-style redirection, you must parse the command, locate the redirection operators, open the files and assign them to input/output descriptors. This must be done before calling execvp. Look up the dup2 system call.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
8

You can use system() if you really want to use that sort of syntax. As you noted, redirection and wildcard expansion and a whole bunch of other things are handled by the shell on Unix-like systems.

The way to do it with fork looks something like this:

int kidpid;
int fd = open("redirected.txt", O_WRONLY|O_TRUNC|O_CREAT, 0644);
if (fd < 0) { perror("open"); abort(); }
switch (kidpid = fork()) {
  case -1: perror("fork"); abort();
  case 0:
    if (dup2(fd, 1) < 0) { perror("dup2"); abort(); }
    close(fd);
    execvp(cmd, args); perror("execvp"); abort();
  default:
    close(fd);
    /* do whatever the parent wants to do. */
}
tmyklebu
  • 13,915
  • 3
  • 28
  • 57
  • You should close `fd` (or _set_ its close-on-exec flag). As it stands, the process gets an extra open file descriptor. Not dreadfully harmful here, but could be a problem in other contexts. – Jonathan Leffler Dec 09 '12 at 03:41
  • @JonathanLeffler: Good catch. I removed the false note at the end, added a close() in the child, and fixed the error-check on dup2(). – tmyklebu Dec 09 '12 at 11:11
3

It seems like the easiest thing to do is:

execlp( "/bin/sh", "/bin/sh", "-c", "cat file1.txt > redirected.txt", (char *)NULL );

You can do the same with execvp.

William Pursell
  • 204,365
  • 48
  • 270
  • 300