newalchemy
newalchemy

Reputation: 61

execvp and reading command arguments

I'm working on a project in which I have to write a command shell for linux in C. So far, it's working for commands with no input (ie, the shell will run the 'date' command and 'ls' command fine.)

However, commands which require some input, it seems like it reads each input as a seperate command. For instance, for the command:

% gcc -o testFile testFile.c

It seems as if the shell is running gcc as its own command, then -o, then testFile, and testfile.c when it should be taking gcc as the command, with the other three entries as inputs.

I don't understand what's going on in the code - and it probably comes from not understanding the execvp function fully (I read about it from several sources and I still don't think I understand it - I thought I did!).

The execvp call is in the function execute.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "commandStorage.c"

#define MAX_ARGUMENTS 10


void parseLine(char *command, char **args) {

const char split = '\0';
int i;
char *ptrToken;

while(*command != '\0') {
    while ((*command == '\n') || (*command == '\t')
        || (*command == ' ')) {
        *(command++) = '\0';
        } // end 'while'
    *args++ = command;
    printf("%s\n", command);
    while ((*command != '\n') && (*command != '\t')
        && (*command != '\0') && (*command != ' ')) {
        command++;
        } // end 'while'

    } // end 'while'
*args = '\0';
} // end parseLine

void execute(char **arrayOfPtrs) {
/*
CURRENT BUG:
The function is taking the array of pointers, and executing each
input from the array seperately.

The execvp function is being misused.
*/
pid_t pid;
int waitStatus;

switch (pid = fork()) {
    case 0:  // Child process
        if (execvp(arrayOfPtrs[0], arrayOfPtrs) < 0) {
            perror("THE COMMAND FAILED TO EXECUTE!");
            break;

            } // end 'if

    case -1:  // Fork failed
        perror("THE PROCESS FAILED TO FORK");
        break;

    default: // Parent process
        while ((wait(&waitStatus) != pid)) {};
        break;
} // end 'switch'
return;
} // end 'execute

void clearPointerArray(char **args){

while (*args != NULL) {
    *(args++) = NULL;
}
}


int main() {

int i;
char command[MAX_STRING_LENGTH]; // unparsed command
pid_t pid;
char *args[MAX_ARGUMENTS]; // Argument vector.


while(1) {
    clearPointerArray(args);
    printf("%s", "TimsShell--> ");
    scanf("%s", command);

    parseLine(command, args);

    if ((strcmp(args[0], "exit") == 0) || (strcmp(args[0], "quit") == 0)) {
        printf("%s\n", "Goodbye!");
        return 0;
    }

    execute(args);

    }// while loop
return 0;

} // main

And here is some output from the commandline:

% gcc -o mainShell mainShell.c
% ./mainShell
TimsShell--> date
date
Fri Feb 14 15:50:28 EST 2014
TimsShell--> ls
ls
change.log      doLocalConf.xml   license.txt   notepad++.exe  session.xml               testFile.c
commandStorage.c  functionList.xml  localization  plugins     shortcuts.xml         themes
config.model.xml  langs.model.xml   mainShell      readme.txt     stylers.model.xml    updater
config.xml      langs.xml        mainShell.c   SciLexer.dll     stylers.xml          user.manual
TimsShell--> gcc -o testFile testFile.c
gcc
gcc: fatal error: no input files
compilation terminated.
TimsShell--> -o
THE COMMAND FAILED TO EXECUTE!: No such file or directory
TimsShell--> testFile
THE COMMAND FAILED TO EXECUTE!: No such file or directory
TimsShell--> testFile.c
: not found 2: testFile.c: 
testFile.c: 3: testFile.c: Syntax error: "(" unexpected
TimsShell--> ^C

Upvotes: 0

Views: 989

Answers (1)

djp
djp

Reputation: 193

Refer to the man page for scanf for why this happening. The problem is in your format string:

%s

Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.

Try this instead:

scanf("%[^\n]s", command);
getchar();

or

scanf(" %[^\n]s", command);

Upvotes: 1

Related Questions