简体   繁体   中英

Passing a pipe as a parameter in exec

I'm trying to pass a pipe to another process, which I create with execv. This is my code so far, but it doesn't work. I've looked everywhere for information, but I can't find anything specifically about passing a pipe vie exec. Any help is appreciated. Thanks

int fd[2];
pipe(fd);

char passwrite[1];
sprintf(passwrite, "%d", fd[0]);

char arg[1];
arg[1]=passwrite;

int x;
x=fork();
if (x==0) {
execv("NewProg",arg);
}

A pipe is a unidirectional connection that usually ends up being between two processes associated by a common ancestor, typically the first of the two processes to be created, unless it is a shell in which case the shell creates the pipe and has two children that use the pipe. The pipe has a write end which is used by one process; it has a read end used by the other. It is often simplest to arrange for the standard output of one process to be connected to the standard input of the other. It is also simplest to use file descriptors rather than standard I/O file streams.

The sequence of operations is:

  1. Call pipe() to create the pipe.
  2. Call fork() to create a child.
  3. The child process (return value 0 from fork() ) does:
    • close() the write end of the pipe
    • dup2() the read end of the pipe to standard input
    • close() the read end of the pipe
    • execve() the child process that will read from the pipe (its standard input)
  4. The parent process (return value > 0 from fork() ) does:
    • close() the read end of the pipe
    • dup2() the write end of the pipe to standard output.
    • close() the write end of the pipe
    • execve() the process that will write to the pipe (its standard output)

Note that in this scenario, you end up closing both the file descriptors returned by the pipe() call, and you close them twice (once in the parent, once in the child).

If the parent process should write to the child via a file stream, use the fdopen() call on the write file descriptor (and don't use dup2() on it, or close() it -- you close it with fclose() on the file stream returned by fdopen() , or by exiting).

If you want to tell the child process which file descriptor number it can read from to get the input from the pipe, then you don't need to do the dup2() in the child; you can simply format up a string in an array of characters (plural - you need at least characters and should allow for a dozen or so, since it is extremely cheap), and you can then arrange to pass the arguments to the execve() function. Remember that the child would need three pointers at minimum: one for argv[0], the program name; one for the file descriptor number; and one for the terminating null pointer. That's how execve() knows when it has reached the end of the argument list. If you are using just execv() , the same comments apply; you just don't get to determine the child's environment (as in, the list of environment variables it receives); it will just get the same environment as the parent process had at the time of the fork() .

The first step in each of ¶3 and ¶4 are the crucial ones. If you omit them, the pipe won't work properly.

There are a couple of potential problems with your code, even before you get to the pipe handling (see Jonathan Leffler's answer for that). First, you need a larger buffer, since a single character isn't enough to hold an integer and the terminating NUL:

char passwrite[10];

Then, arg needs to be an array of pointers, not an array of characters, and it also needs to be bigger:

char *arg[3];

You need to put specific things in the args:

arg[0] = "NewProg"; // name of program
arg[1] = passwrite;
arg[2] = NULL;

The man page for execv on my system explains this in more detail:

The const char *arg and subsequent ellipses in the execl(), execlp(), and execle() functions can be thought of as arg0, arg1, ..., argn. Together they describe a list of one or more pointers to null-terminated strings that represent the argument list available to the executed program. The first argument, by convention, should point to the filename associated with the file being executed. The list of arguments must be terminated by a NULL pointer, and, since these are variadic functions, this pointer must be cast (char *) NULL.

man pipe

Here you can find example of using pipe

You would be required to use dup() system call in order to achieve this.Also you would be required to change the STDIN,STDOUT OF parent and child as per requirement.This is an excerpt from the Unix Shell which i created.

void pipe() {int z;
int w=fork();

 if(w==0)
 {    
     int pfd[2];
     pipe(pfd[2]);
     z=fork();
     if(z==0)
     {
         close(pfd[0]);
         close(1);
         dup(pfd[1]);
         close(pfd[1]);
         execlp(token[0],token[0],NULL);
     }
     else
         {
               close(pfd[1]);
               close(0);
               dup(pfd[0]);
               close(pfd[0]);
               execlp(token[2],token[2],NULL);
         }     
  }
  else
       wait();

}

In above code you need to substitue token[0],token[2] and token[1] which are elements of pointers to strings(in my shell) with the command that you want to run.As i had done parsing of the coomand line in my shell thus had to use Token[0/1/2] for obtaining various command line parameters.But you can substitute them to make this work

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM