开发者

multi pipes in C hang

开发者 https://www.devze.com 2023-03-29 11:05 出处:网络
I am trying to implement program that will run multiple chains of shell commands: --> cmd3 --> cmd4 -->

I am trying to implement program that will run multiple chains of shell commands:

        | --> cmd3 --> cmd4 -->
 cmd2-->|
        | --> cmd5 --> cmd6 -->|--> cmd7
                               |
                               |--> cmd8

and so on...

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <sys/types.h>

typedef struct command {
    char* name;
char** argv;
} command;

command parsecmd(char* cmd) {
    command c;

    char delimiter[] = " ";
    char* buf = malloc(sizeof(char) * strlen(cmd));
    strcpy(buf, cmd);
    char **args = malloc(sizeof(char*));

    char* token = strtok(buf, delimiter);

    int i = 0;
    while (token != NULL) {
      if (i == 0) {
             c.name = token;
          }

      args[i] = token;

      token = strtok(NULL, delimiter);
          ++i;
     }

     args[i] = NULL;

     c.argv = args;

     return c;
}

int mkproc(char *cmd, int outfd)
{
    command c = parsecmd(cmd);
    int pipeleft[2];
    pipe(pipeleft);
    if(!fork()){
        close(pipeleft[1]);
        dup2(pipeleft[0], 0);
        dup2(outfd, 1);
        execvp(c.name, c.argv);
    }
    close(pipeleft[0]);
    return pipeleft[1开发者_运维技巧];
 }

int mktree(char *cmd, int ofd0, ...)
{
    int piperight[2];
    pipe(piperight);

    int cmdin = mkproc(cmd, piperight[1]);
    close(piperight[1]);
    if(!fork()){
        uchar buf[4096];
        int n;

        while((n=read(piperight[0], buf, sizeof buf))>0){
            va_list ap;
            int fd;
            va_start(ap, ofd0);
            for(fd=ofd0; fd!=-1; fd=va_arg(ap, int)){
                write(fd, buf, n);
            }
            va_end(ap);
        }
    }
    return cmdin;
 }

 int main(int argc, char* argv[]) {
       // THIS WORK
       int chain_in = mkproc("cat foo.txt", mkproc("sort", mkproc("wc -l", 1)));
       // THIS WORK
       int tree_in1 = mktree("cat /tmp/test.log", mkproc("grep a", 1), mkproc("wc -l", 2), -1);

       // NOT WORK -> HANG!
       int tree_in2 = mktree("cat /tmp/test.log", 
              mktree("grep test",
                  mkproc("uniq", mkproc("wc -l", 1)),
                  mkproc("wc -l", 2), -1),
              mkproc("sort", 2), -1);
 }

when running strace on the sub processes, it's stuck on read from pipe, when running starce on the main process, it's also stuck on read... The pipe buffer is 64K and I am writing only 4k at once for each pipe

WHAT'S GOING ON?!

THANKS!!!


I can see at least two problems with your code:

char* buf = malloc(sizeof(char) * strlen(cmd));

You need to allocate one more than the length of cmd, for the 0 terminator. Since sizeof(char) is 1 by definition, I would write the above as:

char *buf = malloc(strlen(cmd)+1);

Also, for:

char **args = malloc(sizeof(char*));

You need to allocate space for as many arguments as needed:

char **args = malloc(n * sizeof *args);

where n is the number of arguments.


You're not allocating enough memory for your program arguments. In parsecmd, you're only allocating space for a single pointer in char **args = malloc(sizeof(char*)), and you're subsequently storing more than one pointer in it without reallocating it, resulting in a buffer overrun. Similarly, you're allocating one byte less than you should in char* buf = malloc(sizeof(char) * strlen(cmd))—you need to add one to that in order to have space for the string's terminating NUL. Also, sizeof(char) is guaranteed to be 1 by the C standard, so there's no need to put that in the call to malloc.

Other problems with your code:

  • You're leaking memory. All of your calls to malloc need a corresponding call to free to avoid leaking memory.
  • Add more comments about what your code is doing
  • strtok is not safe to use in multithreaded code, since it uses shared global state. If this code every needs to become thread-safe, consider replacing it with strtok_r(3) if available, or some other replacement.
  • You're failing to handle errors, if fork, execvp, or pipe fails

Fix these problems and see if that solves your hang.

0

精彩评论

暂无评论...
验证码 换一张
取 消