pipin' problems - stdin & stdout messed up after executing piped command

pipin' problems - stdin & stdout messed up after executing piped command

Post by swagat.dasgu.. » Wed, 23 Nov 2005 18:54:39



hi

iv been writing this lightweight shell. just finished writing a
function to implement piping.

the problem is that everytime i call a piped command, the command
executes ok, but afterwards stdin and stout get thrown for a toss.

for example, the prompt doesnt show up. then, if i do enter a command,
both the prompt and command output show up as complete output. i figure
there's a problem with my file descriptor handling in the piping
function.

flushing stdin and stdout dont seem to solve the problem.

code below.

swagat

p.s. the shell aint complete yet... the redirections havent been
implemented, and there are probably fallacies in the main fn.

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define COMMLINESIZ 300 /* Size of command input line/buffer */
#define COMMTOKMAX 20  /* Maximum no. of tokens in command input line
*/
#define COMMINDIVMAX 20 /* Maximum no. of individulal commands in input
line */

int status;

void prompt() {

        fprintf(stdout, "%s:%s$ ", getlogin(), get_current_dir_name());
        fflush(stdout);

}

void tokenize(char *commandLine, char **commandTokens, char
*separators) {

        int index; /* Index for parsing */

        commandTokens[0] = strtok(commandLine, separators);
        for (index = 1; index < COMMTOKMAX; index++) {
                commandTokens[index] = strtok(NULL, separators);
                if (commandTokens[index] == NULL)
                        break;
        }

}

int individualCommandsFn(char *commandLine, char **individualCommands)
{

        char *separators = ";";
        int numOfCommands;

        individualCommands[0] = strtok(commandLine, separators);
        for (numOfCommands = 1; numOfCommands < COMMINDIVMAX ;
numOfCommands++) {
                individualCommands[numOfCommands] = strtok(NULL, separators);
                if (individualCommands[numOfCommands] == NULL)
                        break;
        }
        return numOfCommands;

}

void execute(char *commandLine) {

        char *commandTokens[COMMTOKMAX]; /* Command input line tokens */
        char *separators = " \t\n"; /* Command input token separators */
        int pid, wpid; /* Process ids */

        tokenize(commandLine, commandTokens, separators);

        switch (pid = fork()) {
                case -1:
                        break;
                case 0:
                        execvp(commandTokens[0], commandTokens);
                default:
                        wpid = wait(0);
                        if (wpid < 0)
                                fprintf(stdout, "%s: Invalid command\n", commandTokens[0]);
                        break;
        };

}

void executePipedCommand(char *commandLine) {

        char *prePipeCommandTokens[COMMTOKMAX],
*postPipeCommandTokens[COMMTOKMAX], *pipeIndex;
        char *separators = " \t\n";
        int pid, pid2, wpid;
        int pfd[2];

        pipe(pfd);

        pipeIndex = strchr(commandLine, '|');
        *pipeIndex = '\0';
        pipeIndex++;
        tokenize(commandLine, prePipeCommandTokens, separators);
        tokenize(pipeIndex, postPipeCommandTokens, separators);

        pid = fork();
        if (pid == 0) {
                close(pfd[1]);
                dup2(pfd[0], 0);
                close(pfd[0]);
                execvp(postPipeCommandTokens[0], postPipeCommandTokens);
        } else {
                pid2 = fork();
                if (pid2 == 0) {
                        close(pfd[0]);
                        dup2(pfd[1], 1);
                        close(pfd[1]);
                        execvp(prePipeCommandTokens[0], prePipeCommandTokens);
                } else {// I THINK THE PROBLEM IS SOMEWHERE HERE!!!!
                        close(pfd[0]);
                                                close(pfd[1]);
                        wpid = wait(0);
                }
        }

}

void executeIPRedirCommand(char *commandLine) {

}

void executeOPRedirCommand(char *commandLine) {

}

int isPipingFn(char *commandLine, int *isPiping) {

        char *pipingFirstOcc, *pipingLastOcc;

        if (pipingFirstOcc = strchr(commandLine, '|')) {
                pipingLastOcc = strrchr(commandLine, '|');
                if (pipingFirstOcc != pipingLastOcc) {
                        fprintf(stdout, "Multilevel piping not supported\n");
                        *isPiping = -1;
                } else *isPiping = 1;
        }
        return *isPiping;

}

int isOPRedirectionFn(char *commandLine, int *isOPRedirection) {

        char *opRedirFirstOcc, *opRedirLastOcc;

        if (opRedirFirstOcc = strchr(commandLine, '>')) {
                opRedirLastOcc = strrchr(commandLine, '>');
                if (opRedirFirstOcc != opRedirLastOcc) {
                        fprintf(stdout, "Multilevel output redirection not supported\n");
                        *isOPRedirection = -1;
                } else *isOPRedirection = 1;
        }
        return *isOPRedirection;

}

int isIPRedirectionFn(char *commandLine, int *isIPRedirection) {

        char *ipRedirFirstOcc, *ipRedirLastOcc;

        if (ipRedirFirstOcc = strchr(commandLine, '<')) {
                ipRedirLastOcc = strrchr(commandLine, '<');
                if (ipRedirFirstOcc != ipRedirLastOcc) {
                        fprintf(stdout, "Multilevel input redirection not supported\n");
                        *isIPRedirection = -1;
                } else *isIPRedirection = 1;
        }
        return *isIPRedirection;

}

int main() {

        char commandLine[COMMLINESIZ]; /* Command input line/buffer */
        char *individualCommands[COMMINDIVMAX];
        int isPiping, isIPRedirection, isOPRedirection, numOfCommands, i;

        while(1) {

                prompt();
                fgets(commandLine, COMMLINESIZ, stdin);
                fflush(stdin);

                if (commandLine[0] == '#' || commandLine[0] == '\n')
                        continue;

                numOfCommands = individualCommandsFn(commandLine,
individualCommands);

                for (i = 0; i < numOfCommands; i++) {
                        isPiping = isPipingFn(individualCommands[i], &isPiping);
                        isIPRedirection = isIPRedirectionFn(individualCommands[i],
&isIPRedirection);
                        isOPRedirection = isOPRedirectionFn(individualCommands[i],
&isOPRedirection);

                        if (isPiping == -1 || isIPRedirection == -1 || isOPRedirection ==
-1){
                                continue;
                        }

                        if (isPiping)
                                executePipedCommand(individualCommands[i]);
                        else if (isIPRedirection)
                                executeIPRedirCommand(individualCommands[i]);
                        else if (isOPRedirection)
                                executeOPRedirCommand(individualCommands[i]);
                        else execute(individualCommands[i]);

                        isPiping = isIPRedirection = isOPRedirection = 0;

                }

        }

        return 0;

}

 
 
 

pipin' problems - stdin & stdout messed up after executing piped command

Post by Icarus Sparr » Thu, 24 Nov 2005 00:53:39



> hi

> iv been writing this lightweight shell. just finished writing a
> function to implement piping.

> the problem is that everytime i call a piped command, the command
> executes ok, but afterwards stdin and stout get thrown for a toss.

> for example, the prompt doesnt show up. then, if i do enter a command,
> both the prompt and command output show up as complete output. i figure
> there's a problem with my file descriptor handling in the piping
> function.

> flushing stdin and stdout dont seem to solve the problem.

> code below.

The traditional way to do this is the following pseudo-code

If isPiping
        fork
        if parent then wait
        else
                pipe
                fork
                if child
                        rearrange file descriptors
                        exec one side of pipe
                else
                        rearrange file descriptors
                        exec other side of pipe
                endif
        endif
endif

Note that you fork first, then pipe, then fork, rather than pipe, fork, fork.

Of course on of the things that made ksh a more efficient shell than the
original bourne shell was that it would look at the RHS of a pipe and
see if it could avoid one of the forks.