Home > Software engineering >  Problems with shell implementation in c
Problems with shell implementation in c

Time:12-28

Been working on a simple shell implementation for a for days. But I have 2 issues:

1.When you run the program and type a command like "/bin/ls -l /usr/include" and then press enter it will execute the command but if you then enter a few new lines the program will still go into execvp() and output "Permission denied", because it goes into the error handling of execvp and that's not supposed to happen. (I tried a few different things to stop it from going into the if() in main but they didn't work.)

2.If you type enter and then enter a command the command won't be executed. (I tried freeing the buff and allocating memory again but that caused more issues.)

So basically it goes in the "if(buff[offset] == '\n')" even if the line is empty when it shouldn't and it doesn't execute a command unless its the first input after starting the program.

Code:

int fd = 0;
const size_t read_size = 1;
size_t size = read_size;
char *buff = malloc(size 1);
size_t offset = 0;
size_t res = 0;

write(STDOUT_FILENO, "$ ", strlen("$ "));
while((res = read(fd, buff   offset, read_size)) > 0) 
{
    if(buff[offset] == '\n')
    {
        buff[offset] = '\0';
        char **result = parse_cmdline(buff); // turn string into array for execvp()

        int exec;
        int status;
        pid_t pid = fork();
        if(pid == -1) {/*error handling*/}
        else if(pid == 0)
        {
            if((exec = execvp(result[0], result)) == -1) {/*error handling*/}
        }
        else
        {
            waitpid(pid, &status, 0);
        }

        offset = 0;
        free(result[0]);
        free(result);
        result = NULL;
        write(STDOUT_FILENO, "$ ", strlen("$ "));
    }
    offset  = res;
    if (offset   read_size > size)
    {
        size *= 2;
        buff = realloc(buff, size 1);
    }
    buff[offset] = '\0';
}
free(buff);
return 0;

UPDATE: Works with commands inputted after the first line, but with an error in every case:

"a.out: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed. Aborted (core dumped)"

Updated code:

if(buff[offset] == '\n')
        {
            buff[offset] = '\0';
            char **result = parse_cmdline(buff);
            if(result[0] != NULL)
            {
            int exec;
            int status;
            pid_t pid = fork(); // create the child process
            if(pid == -1) // check for fork() errors (no memory, etc.)
            {
                fork_error();
            }
            else if(pid == 0) // Handle child process
            {
                if((exec = execvp(result[0], result)) == -1) // run the command itself and check if an error will occur (invalid command, etc.)
                {
                    file_error(result[0]);
                }
            }
            else // Handle parent process
            {
                waitpid(pid, &status, 0);
            }

            offset = 0;
            free(buff);
            size = read_size;
            free(result[0]);
            free(result);
            result = NULL;
            }
            write(STDOUT_FILENO, "$ ", strlen("$ "));
            
        }
        else
        {
            offset  = res;
            if (offset   read_size > size)
            {
                size *= 2;
                buff = realloc(buff, size 1);
            }
            buff[offset] = '\0';
        }

CodePudding user response:

Your parse_cmdline() function should test for empty lines, lines with just whote space and comment lines starting with # and return NULL is these cases.

The calling code should then test result for such lines to be ignored.

The calling code should also compare result[0] with the names of internal commands, such as cd or chdir and handle them locally instead of calling fork and exec.

  • Related