Sathvik Swaminathan
Sathvik Swaminathan

Reputation: 179

execve() failing inspite of correct argv vector

I'm trying to implement a basic shell using the given below code. It is throwing an error when trying to load and run a non-builtin command.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <signal.h>
    #include <limits.h>
    #include <readline/readline.h>
    #include <readline/history.h>

    #define MAXARGS 10

    /* Parse input command */ 
    /* return 1 if background process */
    /* return 0 if foreground process */

    int parse_line(char *cmd, char **argv)
    {
        int bg;         /* background or foreground process */
        int argc;       /* number of arguments to be passed to exec */
        char *delim;    /* points to first space occurence in cmd */

        /* Ignore leading spaces in cmd */
        while(*cmd && (*cmd == ' '))
        {
            cmd++;
        }

        /* Build argv list */
        argc = 0;
        while((delim = strchr(cmd, ' ')))
        {
            *delim = '\0';  /* To NULL terminate the token pointer */
            argv[argc++] = cmd;
            cmd = ++delim;
            /* Ignore leading spaces in cmd after token */
            while(*cmd && (*cmd == ' '))
            {
                cmd++;
            }
        }
        /* argv is NULL terminated */
        argv[argc] = NULL;

        int i = 0;

        /* Blank command */
        if(argc == 0)
        {
            return 1;
        }

        /* If background process, return 1 and truncate & from cmd */
        if((bg = (*argv[argc - 1]) == '&'))
        {
            argv[--argc] = NULL;
        }

        return bg;
    }

    int builtin_cmd(char **argv)
    {
        if (!strcmp(argv[0], "exit")) /* quit command */
            exit(0);
        if (!strcmp(argv[0], "&"))
            return 1;               /* Ignore singleton & */
        
        return 0;
    }

    int main()
    {
        char cwd[PATH_MAX]; /* current directory */
        char *cmd;
        char *argv[MAXARGS];
        char *environ[] = { NULL };
        int i = 0;
        pid_t pid;
        int status, bg;

        while(1) 
        {
            if (getcwd(cwd, sizeof(cwd)) != NULL) 
            {
                /* Print prompt and read command */
                printf("%s", cwd);
            } 
            else 
            {
                printf("cwd error\n");
                return 1;
            }

            cmd = readline(": ");
            cmd = (char*)realloc(cmd, sizeof(char)*strlen(cmd));
            /* last character is set to ' ' to parse properly */
            cmd[strlen(cmd)] = ' ';
            bg = parse_line(cmd, argv);

            /* Evaluate command */
            /* Ignore blank command */
            if(argv[0] == NULL)
                return 1;

            /* Fork and exec if not builtin command */
            if(!builtin_cmd(argv))
            {
                if((pid = fork()) == 0)
                {
                    /* Load image of executable in child process */
                    if(execve(argv[0], argv, environ) < 0)
                    {
                        int i = 0;
                        while(argv[i] != NULL)
                        {
                            printf("argv[%d] = %s\n", i, argv[i]);
                            i++;
                        } 
                        printf("execve error\n");
                        free(cmd);
                        return 1;
                    }
                }

                if(pid > 0)
                {
                    /* Shell waits for foreground process to terminate */
                    if(!bg)
                    {
                        if(waitpid(pid, &status, 0) < 0)
                        {
                            printf("waitpid error\n");
                            free(cmd);
                            return 1;
                        }
                    }
                }
            }
        }

        return 0;
    }

For some reason, the execve() command keeps failing. This is my console output: enter image description here

I'm passing the correct parameters to the execve function and the argv vector seems to have the correct parameters and is NULL terminated. I'm unable to spot the error here. Any help is appreciated.

Upvotes: 0

Views: 263

Answers (1)

Employed Russian
Employed Russian

Reputation: 213446

I'm passing the correct parameters to the execve function

No, you are not. execve() will not search your $PATH, and so correctly fails (unless there is an ls executeable file in your current directory).

If you want to search $PATH, use execvpe() or you must search the $PATH yourself and try calling execvp() for each possible candidate in a loop.

Upvotes: 1

Related Questions