passing stdin to a forked process, after writing some data to the process ..

passing stdin to a forked process, after writing some data to the process ..

Post by Chri » Fri, 28 Mar 2003 23:28:19



Hey,
I am writing a wee app to learn some C.

I fork and execute a command. As is, the command seems to get the info
passed on stdin.

What i would like to do, is fork, exec command, write some info to the
command and *then* pass it whats on stdin.

Below is an excerpt from the code i have written to date.

Can anyone give me any tips as to how to do this ?
Much appreciated :)

Chris
--

/**********************************
 * Run maildrop with the correct params

 */
void runMailDrop(recipient_info * recip_info) {
     int pid, status;
     char * arg_str;
     int app_pipe[2];

    /* create the pipe. */
    if (pipe(app_pipe)) {
        fprintf(stderr, "Pipe failed\n");
        exitNicely(recip_info, 1);
    }

    pid = fork();

    /* was the fork successful */
    if (pid < 0) {
         printf("Could not fork\n");
         exitNicely(recip_info, 1);
    }

    /* exec the child process **/
    if (pid==0) {

         /* get the command string */
         sprintf(arg_str, "-d %s -f %s _example_ %s",
                recip_info->username,
                recip_info-sender_addr,
                recip_info->recipient_addr);

         printf("Running maildrop with %s\n", arg_str);

         /* run maildrop */
         if (execlp("/usr/bin/maildrop", arg_str, NULL) == -1) {
             perror("Error running maildrop: execvp");
             exitNicely(recip_info, 1);
         }

        exitNicely(recip_info, 0);

    } else {    // this is the parent

        // write the message over the pipe
       writeMsgToPipe(recip_info, app_pipe[1]);

        // wait for maildrop returning
        while(wait(&status)!= pid);

        // printf("The exit code was %i\n", status);
        exitNicely(recip_info, status);
    }
 }

/**********************************
 * Write from stdin to the maildrop process


 */
void writeMsgToPipe(recipient_info * recip_info, int file) {
  FILE * stream;
  FILE * in_stream;

  // open the file to write to the maildrop
  stream = fdopen(file, "w");

  /** these are the bits i want to put before the stdin **/
  fprintf(stream, "Return-Path: <%s>\n", recip_info->sender_addr);
  fprintf(stream, "Delivered-To: smtp-%s\n", recip_info->recipient_addr);

  /** write stdin to the stream **/
  fprintf(stream, "%s", stdin);

  fclose(stream);

Quote:}

 
 
 

passing stdin to a forked process, after writing some data to the process ..

Post by Marc Rochkin » Fri, 28 Mar 2003 23:39:48



> Hey,
> I am writing a wee app to learn some C.

> I fork and execute a command. As is, the command seems to get the info
> passed on stdin.

> What i would like to do, is fork, exec command, write some info to the
> command and *then* pass it whats on stdin.

> Below is an excerpt from the code i have written to date.

> Can anyone give me any tips as to how to do this ?
> Much appreciated :)

> Chris
> --

> /**********************************
>  * Run maildrop with the correct params

>  */
> void runMailDrop(recipient_info * recip_info) {
>      int pid, status;
>      char * arg_str;
>      int app_pipe[2];

>     /* create the pipe. */
>     if (pipe(app_pipe)) {
>         fprintf(stderr, "Pipe failed\n");
>         exitNicely(recip_info, 1);
>     }

>     pid = fork();

>     /* was the fork successful */
>     if (pid < 0) {
>          printf("Could not fork\n");
>          exitNicely(recip_info, 1);
>     }

>     /* exec the child process **/
>     if (pid==0) {

>          /* get the command string */
>          sprintf(arg_str, "-d %s -f %s _example_ %s",
>                 recip_info->username,
>                 recip_info-sender_addr,
>                 recip_info->recipient_addr);

>          printf("Running maildrop with %s\n", arg_str);

>          /* run maildrop */
>          if (execlp("/usr/bin/maildrop", arg_str, NULL) == -1) {
>              perror("Error running maildrop: execvp");
>              exitNicely(recip_info, 1);
>          }

>         exitNicely(recip_info, 0);

>     } else {    // this is the parent

>         // write the message over the pipe
>        writeMsgToPipe(recip_info, app_pipe[1]);

>         // wait for maildrop returning
>         while(wait(&status)!= pid);

>         // printf("The exit code was %i\n", status);
>         exitNicely(recip_info, status);
>     }
>  }

> /**********************************
>  * Write from stdin to the maildrop process


>  */
> void writeMsgToPipe(recipient_info * recip_info, int file) {
>   FILE * stream;
>   FILE * in_stream;

>   // open the file to write to the maildrop
>   stream = fdopen(file, "w");

>   /** these are the bits i want to put before the stdin **/
>   fprintf(stream, "Return-Path: <%s>\n", recip_info->sender_addr);
>   fprintf(stream, "Delivered-To: smtp-%s\n", recip_info->recipient_addr);

>   /** write stdin to the stream **/
>   fprintf(stream, "%s", stdin);

>   fclose(stream);
> }

Some hints:

1. Assuming the command you are execing is going to read its std input, you
need to make that the reading end of the pipe. So, in the child between the
fork and the exec, use dup2 to make file descriptor 0 the reading end of the
pipe. Then, still in the child, close BOTH pipe file descriptors.

2. Rationalize your error checking. It makes the program easier to read and
is more likely to result in the correct return value being checked. I see at
least three different ways in your program that you're checking for the -1
return from system call:
a) treating it like a boolean,
b) test <0
c) test against -1
I would suggest that you uniformaly check against the exact value (-1 for
most traditional system calls) that the documentation specifies. The <0 and
boolean habits are dangerous... you will get bitten one day by a function
that, for example, also returns a pointer, such as shmat.

--Marc