在Linux上使用管道和I / O重定向的Shell模拟器

时间:2016-03-20 12:33:00

标签: c linux shell redirect pipeline

我正在尝试在Linux上编写一个shell模拟器,它可以执行单进程命令,双进程管道和I / O重定向。 然而,当我正确地执行以下单个过程时,管道存在一些问题。

Copy_STDIO();                                       //Copy the stdio for the restoration.
Redirection();                                      //Determine whether should do Redirection.
Pipeline(); 
Restore_stdio();                                    //Restore the stdio.

以上是我在main中的功能。首先,我在I / O重定向后复制STDIO以进行恢复。然后我将我的文件描述符复制到STD_IN和STD_OUT。然后我执行Pipeline,最后我恢复了STD_IN和STD_OUT。一切听起来都很完美,但事实并非如此。我的OUTPUT重定向失败,这意味着它没有向目标文件写入任何内容(即,如果在单一情况下:ls> 123,123没有显示任何内容),当我的程序仍在运行时。但是当我用exit(EXIT_SUCCESS)终止程序时,它出现!!(如果用ctrl + c,它也失败了),我不知道为什么!

void Redirection()
{
    fd_out = open(filename[0],O_WRONLY | O_TRUNC | O_CREAT,S_IRWXU | S_IRWXG | S_IRWXO);    //O_WRONLY and O_CREAT must use at the same time.
    dup2(fd_out,STD_OUTPUT);
    close(fd_out);
}
void Copy_STDIO()
{
    STDIN_COPY = dup(STD_INPUT);                                //Copy for the stdin and stdout
    STDOUT_COPY = dup(STD_OUTPUT);  
}
void Pipeline()
{
if(pipeline)
{
    pipe(&fd[0]);
    childID=fork(); 

    if(childID==0)
    {

        if(fork()!=0)
        {
            close(fd[1]);
            dup2(fd[0],STD_INPUT);
            close(fd[0]);

            execvp(args2[0],args2);

        }
        else
        {
            close(fd[0]);
            dup2(fd[1],STD_OUTPUT);
            close(fd[1]);

            execvp(args[0],args);

        }

    }

    usleep(5000);                                               
}
}
void Restore_stdio()
{
    dup2(STDIN_COPY,STD_INPUT);                                 //Restore the output and input to the stdin and stdout.
    dup2(STDOUT_COPY,STD_OUTPUT);
    close(STDIN_COPY);
    close(STDOUT_COPY);
}

1 个答案:

答案 0 :(得分:0)

我在您自己的存储库中推送了两个提交,它们包含您需要的修补程序

void Pipelining()
{
   int otherID  = 0;
   childID = 0;
   int childs = 0;
   int ret = 0;
    if(pipeline)
    {
    pipe(fd);
    childID=fork();

       if (childID < 0) {
           fprintf(stderr, "error: 1 ... %s\n", strerror(errno));
           return;
       } else if (childID > 0) {
           ++childs;
           otherID = fork();
           if (otherID < 0) {
               fprintf(stderr, "error: 2 ... %s\n", strerror(errno));
               ret = waitpid(childID, NULL, 0);
               if (ret < 0) {
                   fprintf(stderr, "error: 3 ... %s\n", strerror(errno));
               }
               return;
           } else if (otherID > 0) {
               ++childs;
           } else {
            close(fd[0]);
            ret = dup2(fd[1],STD_OUTPUT);
               if (ret < 0) {
                   fprintf(stderr, "error: 4 ... %s\n", strerror(errno));
               }
            close(fd[1]);

            ret = execvp(args[0], args);
               if (ret < 0) {
                  fprintf(stderr, "error: 5 ... %s\n", strerror(errno));
               }
           }
       } else {
            close(fd[1]);
            ret = dup2(fd[0],STD_INPUT);
           if (ret < 0) {
               fprintf(stderr, "error: 6 ... %s\n", strerror(errno));
           }
            close(fd[0]);

            ret = execvp(args2[0],args2);
           if (ret < 0) {
               fprintf(stderr, "error: 7 ... %s\n", strerror(errno));
           }
       }
       /* now it is safe to close pipe */
       close(fd[0]);
       close(fd[1]);
       /* wait children */
       ret = waitpid(childID, NULL, 0);
       if (ret < 0) {
           if (errno != ECHILD)
               fprintf(stderr, "error: 8 ... %s\n", strerror(errno));
       }
       ret = waitpid(otherID, NULL, 0);
       if (ret < 0) {
           if (errno != ECHILD)
               fprintf(stderr, "error: 9 ... %s\n", strerror(errno));
       }
   }
}

我做了以下更改:

  1. 现在两个孩子都是从同一个顶级父母创建的
  2. 现在,top-parent关闭了他的管道文件描述符副本
  3. 现在,top-parent正确等待其子女
  4. 添加了急需的状态检查