首页 文章

C - dup2()没有执行

提问于
浏览
-1

这是我的第一个问题,所以如果我忽略任何重要的事情我会道歉 . 所以我一直致力于通过分叉处理管道的任务 . 我的代码非常混乱,充斥着printf语句,所以我看到发生了什么 .

我在网上浏览了一下,我想我知道如何处理管道,但我遇到的问题是我的代码跳过除了inFD和outFD之外的任何文件描述符上的dup2() .

这是我的功能代码 . 另外,根据我的理解,我的老师制作了一个名为CHK的宏来检查错误 . 如果有错误(例如dup2返回-1),它将以打印到stderr终止 .

我的包括,全局变量和信号的myhandler()

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <math.h>
#include <signal.h>

// Function calls
void parse(char *w, char **ptrArray, char *inArray, char *outArray, int *pipeArray);
int flagHandler(char **ptrArray, char *inArray, char *outArray);
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray);

// Global Variables
const int STORAGE = 254;
const int MAXITEM = 100;
int inFD;   // file descriptor for <
int outFD;  // file descriptor for >
int complete = 0; // for sighandler
int readDes = 0;
int writeDes = 1;
int numPipes = 0;
int status;
int forCounter = 0;

int fildes[4];
int pipeIndex = 0;

// MetaChar flags
int lessthanSign = 0; // < flag
int greaterthanSign = 0; // > flag
int firstChildFlag = 0;
int lastChildFlag = 0;

void myhandler(int signum)
{
    complete = 1;
}

我的主要功能

int main()
{
    char s[STORAGE]; // array of words
    char *newargv[MAXITEM];
    char inArray[STORAGE]; // for <
    char outArray[STORAGE]; // for >
    int firstCheck;
    int pidBackground; // holds value from fork(), used for background calls
    struct stat st; // for stat(), checks if file exists

    // dynamic array based on numPipes
    // first child doesn't use this array, as it uses newargv[0] and newargv
    // only the middle children and last child use this array, hence 10
    int *pipeArray = malloc(10 * sizeof(int));

    int numLoops = 0;
    int i = 0;

    signal(SIGTERM, myhandler);

    for(;;)
    {
        // Reset flags here
        lessthanSign = 0;
        greaterthanSign = 0;
        pipeSign = 0;
        firstChildFlag = 0;
        lastChildFlag = 0;
        pipeIndex = 0;


        parse(s, newargv, inArray, outArray, pipeArray);
        pipeHandler(newargv, inArray, outArray, pipeArray);
        wait(NULL);
        fflush(NULL);

    } // end for
    printf("Entering killpg; numLoops = %d\n", numLoops);
    killpg(getpid(), SIGTERM);
    printf("p2 terminated.\n");
    exit(0);
}   // end main

主调用解析填充newargv [] . 它还分别用<和>后面的字符串填充inArray []和outArray [] . 检测管道符号时,它会在newargv []上放置一个null,并在pipeArray []中放置一个值,用于在newargv中索引可执行文件的名称 . 我省略了parse()和flagHandler()调用以保持最小化 .

我的parseHandler()函数

int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray)
{
    pid_t firstChild;
    pid_t firstChildBackground;
    pid_t middleChild;
    pid_t lastChild;
    pid_t lastChildBackground;
    int i = 0; // plain integer for for loops

    printf("Initializing pipes\n");
    //pipe(fildes);
    //pipe(fildes + 2);
    for (i = 0; i < (2*numPipes); i+=2)
    {
        printf("pipe initializing; i is %d\n", i);
        if (pipe(fildes + i) < 0)
        {
            perror("pipe initialization failed");
            exit(EXIT_FAILURE);
        }
    }


    fflush(stdout);
    if ((firstChild = fork()) < 0)
    {
        perror("First child's fork failed!");
        exit(EXIT_FAILURE);
    }
    printf("firstChild pid = %d\n", getpid());
    if (firstChild == 0)
    {

        if (firstChildFlag == 1)
        {
            printf("inFD = open...\n");
            inFD = open(inArray, O_RDONLY);
            printf("Doing dup2 inFD\n");
            if (dup2(inFD, STDIN_FILENO) < 0)
            {
                perror("First child's < dup2 failed");
                exit(EXIT_FAILURE);
            }
        }

        printf("doing dup2 fildes[writeDes]\n");
        if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
        {
            perror("First child's dup2 failed");
            exit(EXIT_FAILURE);
        }
        printf("*****doing dup2 fildes[writeDes] was a success!\n");

        for (i = 0; i < 4; i++)
        {
            if (close(fildes[i]) < 0)
            {
                perror("close failed");
                exit(EXIT_FAILURE);
            }
        }
        if (firstChildFlag == 1)
        {
            lessthanSign = 0;
            firstChildFlag = 0;

            if (close(inFD) < 0)
            {
                perror("close inFD failed");
                exit(EXIT_FAILURE);
            }
        }

        writeDes += 2;

        printf("About to execvp first child\n");
        if (execvp(ptrArray[0], ptrArray) < 0)
        {
            perror("execvp failed");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        fflush(stdout);
        if ((middleChild = fork() < 0))
        {
            perror("Middle child's fork failed");
            exit(EXIT_FAILURE);
        }
        printf("middleChild pid = %d\n", getpid());
        if (middleChild == 0)
        {
            if (dup2(fildes[readDes], STDIN_FILENO) < 0)
            {
                perror("Middle child's dup2 on reading failed");
                exit(EXIT_FAILURE);
            }
            if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
            {
                perror("Middle child's dup2 on writing failed");
                exit(EXIT_FAILURE);
            }

            for (i = 0; i < 4; i++)
            {
                if (close(fildes[i]) < 0)
                {
                    perror("close failed");
                    exit(EXIT_FAILURE);
                }
            }

            readDes += 2;
            writeDes += 2;

            if (execvp(ptrArray[pipeArray[0]], ptrArray + pipeArray[0]) < 0)
            {
                perror("Middle child's execvp failed");
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            fflush(stdout);
            if ((lastChild = fork() < 0))
            {
                perror("Last child's fork failed");
                exit(EXIT_FAILURE);
            }
            printf("lastChild pid = %d\n", getpid());
            if (lastChild == 0)
            {
                if (dup2(fildes[readDes], STDOUT_FILENO) < 0)
                {
                    perror("Last child's dup2 on reading failed");
                    exit(EXIT_FAILURE);
                }
                if (lastChildFlag == 1)
                {
                    outFD = open(outArray, O_CREAT | O_RDWR, 0400 | 0200);
                    if (dup2(outFD, STDOUT_FILENO) < 0)
                    {
                        perror("Last child's > dup2 failed");
                        exit(EXIT_FAILURE);
                    }
                }

                for (i = 0; i < 4; i++)
                {
                    if (close(fildes[i]) < 0)
                    {
                        perror("close failed");
                        exit(EXIT_FAILURE);
                    }
                }
                if (lastChildFlag == 1)
                {
                    greaterthanSign = 0;
                    lastChildFlag = 0;
                    if (close(outFD) < 0)
                    {
                        perror("close on outFD failed");
                        exit(EXIT_FAILURE);
                    }
                }

                printf("Execvp last child\n");
                if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0)
                {
                    perror("Last child's execvp failed");
                    exit(EXIT_FAILURE);
                }
                printf("Last child execvp finished\n");
            }
        }
    }


    // Only the parent gets here
    printf("Only the parent should be here\n");
    printf("My pid is %d\n", getpid());
    for (i = 0; i < 4; i++)
    {
        if (close(fildes[i]) < 0)
        {
            perror("close failed");
            exit(EXIT_FAILURE);
        }
    }

    for (;;)
    {
        pid_t pid;
        if (pid = wait(NULL) < 0)
        {
            perror("wait failed");
            exit(EXIT_FAILURE);
        }
        if (pid == lastChild)
        {
            printf("Parent is waiting for lastChild\n");
            break;
        }
    }

    printf("Parent finished waiting. Returning...\n");
    return 0;
}

我在任何叉子之前做过管道(fildes),以便所有孩子和父母都有他们的副本 . 因此,我必须关闭每个子节点中的所有文件描述符(在dup2之后但在execvp之前)和父节点 . 然后父母将等到它获得lastChild的pid .

有了很多printf语句,我发现没有子进行dup2()命令(当标志合适时,dup2(inFD ...)和dup2(outFD ...)除外) . 也没有打印错误 .

我打印出我的(char)newargv []和我的(int)pipeArray [],它们包含正确的值 . 这似乎只是dup2问题,我完全不知道它出了什么问题 .

我创建了一个名为test2的简单文本文件,其中包含ls |排序| cat someString其中someString只是一个带有文本的文件 . 使用pipeHandler()函数中的所有print语句,我的输出是:

编辑:我修了几个错字 . 我忘了在3 ifs上添加一组额外的括号,if((firstChild = fork()0 <0)

我现在有一个无限循环,因为父亲正在等待lastChild的pid . 这是输出:

Initializing pipes
numpipes = 2
pipe initializing; i is 0
pipe initializing; i is 2
firstChild pid = 20521
firstChild pid = 20522
doing dup2 fildes[writeDes]
middleChild pid = 20521
middleChild pid = 20523
lastChild pid = 20521
Only the parent should be here
My pid is 20521
lastChild pid = 20524
 <infinite loop>

关于发生了什么或者什么可能阻止孩子,我仍然无能为力 .

1 回答

  • 1

    @MarkPlotnick你是对的!并不是dup2没有执行任何东西 . 因为我做了dup2(fildes [1],STDOUT_FILENO),所有打印语句都会被管道传输 .

    我修正了提到的拼写错误 . 我尝试了我老师的测试文件<input1 cat |> your.outputc tr a-z A-Z | tr \ q哪个应该是一个名为your.outputc的文件 . 它确实,并且内容是input1和tr的效果 . 但是,我也在此文件的顶部有printf语句 .

    我认为dup2没有工作,因为没有跟随printf语句,不像在dup2(inFD,STDIN_FILENO)中那样,但这可能是因为它是STDIN .

相关问题