clinuxshellxv6

Why is exec() not working in child fork Xv6?


I am very new to using C and Xv6. I am trying to create a shell within Xv6 that can run simple commands. However, when I use fork(), my exec() function doesn't seem to do anything.

CODE:

#include "kernel/types.h"
#include "user/user.h"


int getCmd(char *buf, int buflen){
    fprintf(1, ">>>");
    gets(buf, buflen);
    printf("%s", buf);
    if (buf[0] == '\n' || buf[0] == ' ')
    {
        fprintf(2, "Please enter a command \n");
        return 0;
    }
    return 1;
}

int forking(void){
    int pid;
    pid = fork();
    if (pid < 0){
        fprintf(2, "fork failed");
        exit(0);
    }
    return pid;
}

void exec_line(char *buf){

        char cmdstr[10][10];
        for (int i = 0; i < strlen(buf); i++)
        {
            cmdstr[0][i] = buf[i];
        }
        char *str[2];
        cmdstr[0][(strlen(cmdstr[0]) - 1)] = '\0';
        str[0] = cmdstr[0];
        printf("HRE1 %s,\n", str[0]);
        exec(str[0], str);
        printf("HRE2 %s,\n", str[0]);
        exit(0);


}

int main(int argc, char *argv[])
{
    char buf[512];
    int buflen = sizeof(buf);
    int a = 0;
    while (a == 0){
        if (getCmd(buf,buflen) == 1){
            if (forking() == 0){
                exec_line(buf);
            } else{
                wait(0);
            }
            
        }

    }

    exit(0);
}

Output:

>>>ls

ls

HRE1 ls

HRE2 ls

It seemed to work fine when it wasn't in the child fork. Would appreciate any help with this!


Solution

  • If the xv6 exec function is anything like the Posix exec* functions that takes an array of char*, the last pointer should point at NULL.

    Your last pointer, str[1], is uninitialized - so it could point anywhere, and the program will (if the pointer doesn't happen to point at NULL) have undefined behavior.

    Add:

    str[1] = NULL;
    

    before calling

    exec(str[0], str);
    

    and also add perror(str[0]); after calling exec to get a clue about why it couldn't start the program in case it still fails.


    Another option is to initialize all pointers when you define str:

    char *str[2] = {0};
    

    or skipping the whole copying into cmdstr:

    char *str[2] = {buf}; // the second char* will be NULL
    

    But: It's customary to provide the program name to the program you start so I suggest:

    char *str[3] = {buf, buf}; // the third char* will be NULL