Find the answer to your Linux question:
Results 1 to 6 of 6
I want to execute a Perl code in memory from my C application, just opening Perl interpreter and send code to its stdin. So, my code is: Code: char *perl_args[] ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Linux Newbie
    Join Date
    Apr 2010
    Location
    Novosibirsk, Russia
    Posts
    145

    Post IPC: need redefine stdin


    I want to execute a Perl code in memory from my C application, just opening Perl interpreter and send code to its stdin. So, my code is:
    Code:
    char *perl_args[] = { "/usr/bin/perl", NULL };
    char *envp = {"INVOKER=myapp", NULL };
    char *code = "print 'Hello!';";
    int pipe_fd[2];
    
    pipe(pipe_fd);
    
    write(pipe_fd[1], (void*) code, strlen(code));
    
    pid_t new_pid = fork();
    
    if(!new_pid)
    {
    dup2(pipe_fd[0], STDIN_FILENO);
    
    execve(perl_args[0], perl_args, envp);
    
    perror("execve error");
    }
    
    close(pipe_fd[1]);
    wait((int*)0);
    but program just hangs up and never ends. Where I am wrong?.. I tried to `strace` bash when executing
    Code:
    echo 'print "HELLO!";' | perl
    and it seems to me that it uses the same actions that I try to do in my code.

  2. #2
    Linux Newbie
    Join Date
    Apr 2010
    Location
    Novosibirsk, Russia
    Posts
    145

    Smile

    Okay, I found 'popen()' function, and I could pass data to a program...but in this way I cannot control its stdout
    I still don't understand why the 'fork()' variant does not works. When I create an unnamed pipe, I do not use any buffered i/o calling 'write()' directly and closing write end of a pipe after it. But child program still continues waiting. Neither fflush(), write_unbuffered() or fsync() does not help. If UNIX was constructed for making IPC easy and to make small programs work together, why it's so hard to make it work? and why nobody knows how to do it?..) should I dig bash source code by myself to know it?..

  3. #3
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,662
    Your problem is probably here:
    Code:
    if(!new_pid)
    {
        dup2(pipe_fd[0], STDIN_FILENO);
        execve(perl_args[0], perl_args, envp);
        perror("execve error");
    }
    
    close(pipe_fd[1]); /* Don't close pipe unil wait() detects the end of the child process. */
    wait((int*)0);
    Try this instead:
    Code:
    if(!new_pid)
    {
        dup2(pipe_fd[0], STDIN_FILENO);
        execve(perl_args[0], perl_args, envp);
        perror("execve error");
    }
    else
    {
        waitpid(new_pid, 0, 0);
        close(pipe_fd[1]);
    }
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  4. $spacer_open
    $spacer_close
  5. #4
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,662
    One other thing. You should not write to pipe_fd[1] in the parent until in the parent part of the process after the fork(). Also, in the child part, close pipe_fd[1] before exceve(). In the parent part, close pipe_fd[0], and then write to pipe_fd[1], close pipe_fd[1], waitpid(), and then exit. So, this is better:
    Code:
    char *perl_args[] = { "/usr/bin/perl", NULL };
    char *envp = {"INVOKER=myapp", NULL };
    char *code = "print 'Hello!';";
    int pipe_fd[2];
    pid_t new_pid = 0;
    pipe(pipe_fd);
    new_pid = fork();
    if(!new_pid)
    {
        close(pipd_fd[1]);
        dup2(pipe_fd[0], STDIN_FILENO);
        execve(perl_args[0], perl_args, envp);
    
        /* Error starting perl - clean up here */
        perror("execve error");
        close(pipe_fd[0]);
    }
    else
    {
        close(pipe_fd[0]);
        write(pipe_fd[1], (const void*) code, strlen(code));
        close(pipe_fd[1]);
        waitpid(new_pid, 0, 0); /* Optionally, use wait(0) */
    }
    A decent overview for use of pipes is found in the section 7 man page for pipe: man 7 pipe
    and man 2 pipe has a good example of use of pipes for IPC in a situation similar to what you are trying to do.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  6. #5
    Linux Newbie
    Join Date
    Apr 2010
    Location
    Novosibirsk, Russia
    Posts
    145

    Post

    Thanks a lot, it works now! at last I understood how the unix-like I/O works by reading some books in addition to your post ) thanks for the light in my head)

  7. #6
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,662
    Yeah. A brick (upside the head) works much the same for me!
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •