예제 #1
0
파일: parse.c 프로젝트: henrydavidge/Parse
//parses a pipeline, returning command struct
//modifies global variable t
CMD *pipeline()
{
	CMD *cmd = 0, *tmp = 0;
	cmd = stage();
	while (t && ISPIPE(t->type))
	{
		if (!cmd)
		{
			DIE("Parse: null command\n");
			freeCMD(cmd);
			return 0;
		}
		if (cmd->toType != NONE)
		{
			DIE("Parse: two output redirects\n");
			freeCMD(cmd);
			return 0;
		}
		tmp = cmd;
		cmd = mallocCMD();
		cmd->type = t->type;
		cmd->left = tmp;
		t = t->next;
		cmd->right = pipeline();
		if (!cmd->right)
		{
			DIE("Parse: null command\n");
			freeCMD(cmd);
			return 0;
		}
	}
	return cmd;
}
예제 #2
0
// Executes a <pipeline> rooted with cmd and returns the status of the last
// command executed.
int processPipeline(CMD* cmd)
{
    assert(cmd);
    assert(ISPIPE(cmd->type) || cmd->type == SIMPLE || cmd->type == SUBCMD);
    
    if(ISPIPE(cmd->type))
    {
        int pipeStatus = execPipe(cmd);
        updateStatusVar(pipeStatus);
        return pipeStatus;
    }
    else
    {
        return processStage(cmd);
    }
}
예제 #3
0
CMD *parsePipeline(token **lstHead)
{
	CMD *cmd = parseStage(lstHead);
	if(cmd->type == ERROR)
	{
		//propagate an error
		return cmd;
	}

	//check to make sure that end of linked list not reached and cmd not NULL!
	if(cmd && *lstHead && ISPIPE((*lstHead)->type))
	{
		CMD *stageCMD = cmd;
		cmd = mallocCMD();
		cmd->type = (*lstHead)->type;
		cmd->left = stageCMD;
		*lstHead = (*lstHead)->next;
		if(*lstHead == NULL)
		{
			//error..incomplete pipeline!
			fprintf(stderr,"%s\n","Error: Incomplete pipeline command");
			return errorCMD(cmd);
		}
		cmd->right = parsePipeline(lstHead);

		if(cmd->right == NULL)
		{
			//case of no right argument for pipe
			fprintf(stderr,"%s\n","Error: Incomplete pipeline command");
			return errorCMD(cmd);
		}

		if(cmd->right->type == ERROR)
		{
			//propagate along an error
			return cmd->right;
		}

		if(stageCMD->toFile != NULL || cmd->right->fromFile != NULL)
		{
			//case of multiple redirections involving a pipeline
			fprintf(stderr,"%s\n","Error: Multiple redirections");
			return errorCMD(cmd);
		}
	}
	return cmd;
}
예제 #4
0
파일: parse.c 프로젝트: danieltahara/Csh
CMD* make_stage(token_list** list_ref)
{
    token_list* list = *list_ref;
    if (!list) return make_error_cmd("could not form stage (no tokens)");

    CMD* stage_tree = mallocCMD(); // Current type is NONE

    int next_type = NONE; // Hold the type of the head token of list
    bool redir_in = false; // Has there been a previous input redirection?
    bool redir_out = false;

    // Loop until hit a pipe or a separator; raise an error if multiple redirect
    // or both a command and subcommand
    while ((next_type = type(list)) != -1 &&
        !ISSEP(next_type) && !ISPIPE(next_type) && next_type != PAR_RIGHT) {

        bool error = false; // Signals whether the current action results in an
                            // error
        if (next_type == SIMPLE && stage_tree->type != SUBCMD) {
            int argc = stage_tree->argc + 1;
            char** argv = stage_tree->argv;
            argv = realloc(argv, (argc + 1) * sizeof(char*)); // +1 for trailing
                                                              // NULL required
                                                              // by freeCMD
            argv[argc - 1] = strdup(text(list));
            argv[argc] = NULL;
            stage_tree->argc = argc;
            stage_tree->argv = argv;
            stage_tree->type = SIMPLE;
        } else if ((next_type == RED_IN || next_type == RED_HERE)
            && !redir_in) {
            error = make_redirect(stage_tree, &redir_in, next_type, &list);
        } else if (ISREDOUT(next_type) && !redir_out) {
            error = make_redirect(stage_tree, &redir_out, next_type, &list);
        } else if (next_type == PAR_LEFT &&
            stage_tree->type == NONE) { // Can't have two subcommands in a stage

            advance(&list); // Advance past left parentheses

            CMD* subcmd_tree = make_cmd(&list);
            error = subcmd_tree->type == ERROR || type(list) != PAR_RIGHT;

            stage_tree->type = SUBCMD;
            stage_tree->left = subcmd_tree;
        } else {
            error = true;
        }

        if (error) {
            freeCMD(stage_tree);
            return make_error_cmd("Invalid stage");
        }

        advance(&list);
    }

    // Make sure we didn't double-redirect
    if (ISPIPE(next_type) && redir_out) {
        freeCMD(stage_tree);
        return make_error_cmd("Double redirect - pipe and >");
    }

    // Make sure there was actually an argument
    if (stage_tree->type == NONE) {
        freeCMD(stage_tree);
        return make_error_cmd("No arguments for simple command");
    }

    assert(stage_tree->type != NONE);

    *list_ref = list;
    return stage_tree;
}
예제 #5
0
// Executes a pipeline and returns the exit status of the pipe. The arg
// pipeRoot is the PIPE or PIPE_ERR command at the root of the pipeline.
// This function draws upon code from Professor Stan Eisenstat at Yale
// University
int execPipe(CMD* pipeRoot)
{
    // count the number of stages in the pipeline
    int numStages = 1;
    for(CMD* cmd = pipeRoot; ISPIPE(cmd->type); cmd = cmd->right, numStages++);
    
    // create table to hold pid and exit status of all stages in the pipe
    struct {
        int pid, status;
    } processTable[numStages];
    
    int fd[2];             // holds file descriptors for the pipe
    int pid, status;       //   the pid and status of a single stage
    int fdIn = STDIN_FD;   //   the read end of the last pipe, or the original
                           //   stdin
    
    CMD* cmd = pipeRoot;
    for(int i = 0; ISPIPE(cmd->type); cmd = cmd->right, i++)
    {
        if(pipe(fd) < 0 || (pid = fork()) < 0)
        {
            perror(EXEC_NAME);
            return errno;
        }
        else if(pid == 0)
        {
            // child
            close(fd[0]);
            
            // redirect stdin to the last pipe read (if there was a last pipe)
            if(fdIn != STDIN_FD)
            {
                dup2(fdIn, STDIN_FD);
                close(fdIn);
            }
            
            bool shouldCloseFD1 = false;
            // redirect stdout to the new pipe write (if it's not stdout)
            if(fd[1] != STDOUT_FD)
            {
                dup2(fd[1], STDOUT_FD);
                shouldCloseFD1 = true;
            }
            
            // if this is a PIPE_ERR, redirect stderr to the new pipe write
            // (if it's not stderr)
            if(cmd->type == PIPE_ERR && fd[1] != STDERR_FD)
            {
                dup2(fd[1], STDERR_FD);
                shouldCloseFD1 = true;
            }
            
            if(shouldCloseFD1) close(fd[1]);
            
            exit(processStage(cmd->left));
        }
        else
        {
            // parent
            processTable[i].pid = pid;
            
            // close the read end of the last pipe if it's not the orig stdin
            if(i > 0)
            {
                close(fdIn);
            }
            
            fdIn = fd[0]; // remember the read end of the new pipe
            close(fd[1]);
        }
    }
    // cmd is now the right child of last PIPE or PIPE_ERR, the last stage of
    // the pipeline
    
    // if the last stage is a built-in command, it should affect the parent
    // shell, so execute it here instead of forking off a process
    if(cmd->type == SIMPLE && IS_BUILTIN(cmd->argv[0]))
    {
        processTable[numStages - 1].pid = -1; // unused pid
        processTable[numStages - 1].status = processSimple(cmd, false);
        close(fdIn);
    }
    else if((pid = fork()) < 0)
    {
        perror(EXEC_NAME);
        return errno;
    }
    else if(pid == 0)
    {
        // child
        if(fdIn != STDIN_FD)
        {
            dup2(fdIn, STDIN_FD);
            close(fdIn);
        }
        exit(processStage(cmd));
    }
    else
    {
        // parent
        processTable[numStages - 1].pid = pid;
        close(fdIn);
    }
    
    // wait for children to die
    signal(SIGINT, SIG_IGN);
    for(int i = 0; i < numStages; )
    {
        pid = wait(&status);
        int j;
        for(j = 0; j < numStages && processTable[j].pid != pid; j++);
        
        // only add to the processTable if the child's pid is in the table;
        // that is, ignore zombies
        if(j < numStages)
        {
            processTable[j].status = status;
            i++;
        }
    }
    signal(SIGINT, SIG_DFL);
    
    for(int i = 0; i < numStages; i++)
    {
        if(GET_STATUS(processTable[i].status) != 0)
        {
            return GET_STATUS(processTable[i].status);
        }
    }
    return 0;
}