sunstror
sunstror

Reputation: 3

Implementing a simple shell in c - wc command not working

I am implementing a simple shell in c for a class. There are a number of requirements but the one thing that I am concerned about is this sequence of commands:

ls > test

wc < test

which will output the results of the ls command to the file test and the wc command will then count the number of words, bytes, characters (or something like that) in that file.

Anyway, the first command works and the test file is successfully created with the expected content. The wc command doesn't work however. It triggers the error associated with the execv statement "Command can't be executed. My input redirection works as a command like: grep test < test works perfectly. My question is, Why doesn't my shell recognize the wc command?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>

void parse(char buffer[2048], char *arguments[512]){
    //these characters(space, tab, new line, return)represent white space
    //that separate words
    char * delim = " \t\r\n\f";
    char * token;
    int count = 0;
    //Finds the first word in buffer
    token = strtok (buffer, delim);
    //While a token still exists
    while (token != NULL){
        //if token is not empty it is added to arguments
        if (strlen (token) > 0){
            arguments[count]=token;
            count++;
        }
        //Find the next token.
        token = strtok (NULL, delim);

        arguments[count+1]=NULL;
    }

int checkInput(char *arguments[512]){
    int loc = 0;
    int count = 0;
    while (arguments[count]!=NULL){
        if (strcmp(arguments[count],"<")==0){
            loc = count;
        }
        count++;
    }
    return loc;
}

void redirectInput(int input,char *arguments[512]){
    int in;
    int in2;
    char*inFile = arguments[input+1];

    in = open(inFile, O_RDONLY);
    if (in < 0){
        perror("Error Opening File");
        exit(1);
    }
    in2 = dup2(in, 0);
    if (in2 < 0){
        perror("Error redirecting stdin");
        exit(1);
    }
    close(in);
}

int checkOutput(char *arguments[512]){
    int loc = 0;
    int count = 0;
    while (arguments[count]!=NULL){
        if (strcmp(arguments[count],">")==0){
            loc = count;
        }
        count++;
    }
    return loc;
}

void redirectOutput(int output,char *arguments[512]){
    int out;
    int out2;
    char*outFile=arguments[output+1];

    out = open(outFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
    if (out < 0){
        perror("Error Opening File");
        exit(1);
    }
    out2 = dup2(out, 1);
    if (out2 < 0){
        perror("Error redirecting stdout");
        exit(1);
    }
    close(out);
}

int main(int argc, char **argv){
    //buffer is to hold the commands that the user will type in
    char buffer[512];
    char buffer2[512];
    //bin/program_name is the arguments to pass to execv
    //if we want to run ls, "/bin/ls" is required to be passed to execv()
    char* path = "/bin/";
    char * arguments[512];
    char * args_copy[512];
    //This will be the final path to the program is passed to execv
    char prog[512];
    char directory[512];
    pid_t pid,w;
    int status;
    int isValid;
    int input;
    int output;

    getcwd(directory,sizeof(directory));

    while(1){
        isValid = 0;
        while(!isValid){
            //print the prompt
            printf(":");
            fflush(stdout);
            //get input
            fgets(buffer, 512, stdin);
            if(buffer[0]!='\n' && buffer[0] != '#'){
                isValid=1;
            }
        }

        strcpy(buffer2, buffer);
        parse(buffer2, args_copy);
        //Handle the builtin functions without before forking
        if (strcmp(args_copy[0],"exit")==0){
            exit(0);
        }
        else if (strcmp(args_copy[0],"status")==0){
            printf("exit value %d\n",WEXITSTATUS(status));
        }else if( strcmp(args_copy[0],"cd") == 0 ){
            if(args_copy[1]==NULL){
                chdir(directory);
            }
            else{
                chdir(args_copy[1]);
            }
        }
        else{
            //fork!
            pid = fork();
            //Error checking to see if fork works
            if (pid < 0) {
                perror("fork");
                exit(EXIT_FAILURE);
            }
            //If pid !=0 then it's the parent
            if(pid!=0){
                do {
                    w = waitpid(pid, &status, WUNTRACED | WCONTINUED);
                    if (w == -1) {
                        perror("waitpid");
                        exit(EXIT_FAILURE);
                   }
                   if (WIFEXITED(status)) {
                   }
                   else if (WIFSIGNALED(status)) {
                       printf("killed by signal %d\n", WTERMSIG(status));
                   }
                   else if (WIFSTOPPED(status)) {
                       printf("stopped by signal %d\n", WSTOPSIG(status));
                   }
                   else if (WIFCONTINUED(status)) {
                       printf("continued\n");
                   }
                }while (!WIFEXITED(status) && !WIFSIGNALED(status));
            }
            else{
                //parse the user input into an array of strings(arguments)
                parse(buffer, arguments);
                input = checkInput(arguments);

                if (input){
                    redirectInput(input,arguments);
                    arguments[input]=NULL;
                }

                output = checkOutput(arguments);

                if (output){
                    redirectOutput(output,arguments);
                    arguments[output]=NULL;
                }
                //First we copy a /bin/ to prog
                strcpy(prog, path);
                //Then we concancate the program name to /bin/
                //If the program name is ls, then it'll be /bin/ls
                strcat(prog, arguments[0]);
                //pass the prepared arguments to execv and we're done!
                int rv=execv(prog, arguments);
                if (rv == -1) {
                    perror("Command can't execute");
                    exit(EXIT_FAILURE);
                }
            }
        }
    }
    return 0;
}

Upvotes: 0

Views: 2543

Answers (1)

that other guy
that other guy

Reputation: 123550

This happens because wc is /usr/bin/wc, not /bin/wc.

You can use execvp instead of execv to automatically search through $PATH for your executable. In that case, you would not add /bin/ to the path.

Upvotes: 3

Related Questions