dup2() not executing

This is my first question so I apologize if I'm omitting anything important. So I've been working on an assignment that handles piping via forking. My code is pretty messy, littered with printf statements so I see what's going on.

I've looked around online and I think I get the idea of how to handle piping, but the problem I'm having is that my code skips dup2() on any file descriptor except inFD and outFD.

Here's the code for my function. Also, from what I understand, my teacher made a macro called CHK which checks for errors. If there is an error (such as dup2 returning -1), it'll terminate with a print to stderr.

My includes, global variables and myhandler() for signal

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

My main function

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 = %dn", numLoops);
    killpg(getpid(), SIGTERM);
    printf("p2 terminated.n");
    exit(0);
}   // end main

Main calls parse which fills in newargv[]. It also fills in inArray[] and outArray[] with the string immediately after a < and > respectively. When detecting a pipe sign, it puts a null on newargv[], as well as putting a value in pipeArray[] for indexing the executable's name in newargv. I omitted the parse() and flagHandler() calls to keep it minimal.

My parseHandler() function

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 pipesn");
    //pipe(fildes);
    //pipe(fildes + 2);
    for (i = 0; i < (2*numPipes); i+=2)
    {
        printf("pipe initializing; i is %dn", 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 = %dn", getpid());
    if (firstChild == 0)
    {

        if (firstChildFlag == 1)
        {
            printf("inFD = open...n");
            inFD = open(inArray, O_RDONLY);
            printf("Doing dup2 inFDn");
            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 childn");
        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 = %dn", 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 = %dn", 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 childn");
                if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0)
                {
                    perror("Last child's execvp failed");
                    exit(EXIT_FAILURE);
                }
                printf("Last child execvp finishedn");
            }
        }
    }


    // Only the parent gets here
    printf("Only the parent should be heren");
    printf("My pid is %dn", 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 lastChildn");
            break;
        }
    }

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

I did pipe(fildes) before any fork, so that all children and a parent have their copy. Therefore, I must close all file descriptors in each child (after dup2 but before execvp) and the parent. The parent will then wait until it gets the pid of lastChild.

With a lot of printf statements, I have found that no child does the dup2() command (except for dup2(inFD...) and dup2(outFD...) when the flags are appropriate). There is also no error printed.

I printed out my (char) newargv[] and my (int) pipeArray[] and they contain the correct values. It seems to be just the dup2 problem, and I have absolutely no idea what's going wrong with it.

I made a simple text file called test2 containing ls | sort | cat someString Where someString is just a file with some text. With all the print statements in the pipeHandler() function my output is:

EDIT: I fixed a couple typos I had. I forgot to lace an extra set of parenthesis on 3 ifs, if ((firstChild = fork()0 < 0)

I now have an infinite loop as the parent is waiting for the lastChild's pid. Here's the output:

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>

I'm still clueless though as to what's going on or what's potentially stopping the child.


@MarkPlotnick you're right! It's not that dup2 isn't executing or anything. Because I did dup2(fildes[1], STDOUT_FILENO), all print statements will be piped.

I fixed the typo mentioned as well. I tried my teacher's test file < input1 cat|>your.outputc tr az AZ | tr q Which should result with a file called your.outputc. It does, and the contents are input1 with the effects of tr. However, I also have the printf statements at the top of this file.

I assumed the dup2 wasn't working because no printf statement followed, unlike it did in dup2(inFD, STDIN_FILENO), but that's probably because it was STDIN.

链接地址: http://www.djcxy.com/p/86038.html

上一篇: 打印分段故障原因

下一篇: dup2()不执行