0

複数のシェル コマンド チェーンを実行するプログラムを実装しようとしています。

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

等々...

#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);
 }

サブプロセスでstraceを実行すると、パイプからの読み取りでスタックし、メインプロセスでスタースを実行すると、読み取りでもスタックします...パイプバッファーは64Kで、パイプごとに一度に4kしか書き込んでいません

どうしたの?!

ありがとう!!!

4

2 に答える 2

0

あなたのコードには少なくとも 2 つの問題があります。

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

ターミネータにはcmd,の長さよりも 1 つ多く割り当てる必要があります。は定義上 1 であるため、上記を次のように記述します0sizeof(char)

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

また、次の場合:

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

必要な数の引数にスペースを割り当てる必要があります。

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

n引数の数です。

于 2011-08-21T20:01:32.893 に答える
0

プログラムの引数に十分なメモリを割り当てていません。ではparsecmd、 の 1 つのポインターにスペースを割り当てているだけでchar **args = malloc(sizeof(char*))、その後、再割り当てせずに複数のポインターを格納しているため、バッファー オーバーランが発生します。同様に、必要なバイト数よりも 1 バイト少なく割り当てていますchar* buf = malloc(sizeof(char) * strlen(cmd))。文字列の終端の NUL のためのスペースを確保するために、それに 1 を追加する必要があります。また、sizeof(char)は C 標準で 1 であることが保証されているため、 の呼び出しに入れる必要はありませんmalloc

コードに関するその他の問題:

  • あなたはメモリをリークしています。メモリリークを避けるために、すべての呼び出しにmalloc対応する呼び出しが必要です。free
  • コードの動作に関するコメントを追加する
  • strtok共有グローバル状態を使用するため、マルチスレッド コードで使用するのは安全ではありません。このコードをすべてスレッドセーフにする必要がある場合はstrtok_r(3)、可能な場合はそれを置き換えるか、他の代替品に置き換えることを検討してください。
  • 、 、または失敗した場合fork、エラーの処理に失敗していますexecvppipe

これらの問題を修正して、ハングが解決するかどうかを確認してください。

于 2011-08-21T20:01:48.380 に答える