execve - No such file or directory?

28,151

Solution 1

The first thing I would do would be to insert:

printf ("[%s]\n", path);

before the call to execve. That should confirm that the executable is what you think it is.

That code of yours looks okay as long as the input you're feeding into it is correct and the executable actually is available. For example, the following complete program works fine on my Debian box:

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main (int argc, char *argv[]) {
    if (argc > 1) {
        char * word = strtok (argv[1], " ");
        char path[128] = "/bin/";
        strcat (path, word);

        char * newenvp[] = { NULL };
        char * newargv[] = { path, NULL };
        printf ("[%s]\n", path);
        int ret = execve (path, newargv, newenvp);
        if (ret == -1) {
            perror("execve error");
        }
    }
    return 0;
}

outputting, when I run ./testprog ls, something along the lines of:

[/bin/ls]
kidsshares.ods  paxwords    birthdays    homeloantracking.gnumeric
shares2011.ods  backup0.sh  development  lexar
accounts.ods    backup1.sh  photos       testprog.c
testprog

Solution 2

If you don't want to manually travel through the fileystem to find the correct binary, there is execlp (with an additional p). From the manpage:

The execlp(), execvp(), and execvpe() functions duplicate the actions of the shell in searching for an executable file if the specified filename does not contain a slash (/) character. The file is sought in the colon-separated list of directory pathnames specified in the PATH environment variable. If this variable isn't defined, the path list defaults to the current directory followed by the list of directories returned by confstr(_CS_PATH). (This confstr(3) call typically returns the value "/bin:/usr/bin".) [...]

Share:
28,151
theeggman85
Author by

theeggman85

-

Updated on July 15, 2022

Comments

  • theeggman85
    theeggman85 almost 2 years

    I'm having some problems with execve. I'm trying to make a shell that can function just like the bash shell, but I have problems with the forked child executing a command. Here is what I have for the child. cmd is a char * with the command that the user typed in. However, when I run this program, I get this error from perror:

    execve error: No such file or directory.
    

    I have tried the program with a simple ls, and it should make path="/bin/ls" and execute it (I have confirmed this is where my ls command is) but it still complains. What am I doing wrong? Thanks!

    if(pid == 0)
    {
        // Parse the command
        char * word = strtok(cmd, " ");
        char path[128] = "/bin/";
        strcat(path, word);
    
        // Execute the process
        char * newenvp[] = { NULL };
        char * newargv[] = { path, NULL };
        ret = execve(path, newargv, newenvp);
    
        if(ret == -1)
            perror("execve error");
    
        return EXIT_SUCCESS;
    }
    
    • geekosaur
      geekosaur about 12 years
      Have you checked that path contains what you think it does? Especially given that strtok() is somewhat notoriously annoying in the way it operates, and can easily produce garbage if you don't play precisely by its rules?
    • Ernest Friedman-Hill
      Ernest Friedman-Hill about 12 years
      Nothing wrong that I can see. Why not throw in a printf() to display the final contents of path to make sure the strtok is doing the right thing -- the execve call itself looks fine.
    • Jonathan Leffler
      Jonathan Leffler about 12 years
      Why are you setting the environment to empty? You should probably use plain execv() to use your current environment, or pass environ as the third argument to execve(). I doubt if this is the source of your problem, but it is better practice. (Also, it is often sensible to use execv(newargv[0], newargv); or execve(newargv[0], newargv, environ);. And there's no point in testing the return status of any of the exec*() functions: if it returned, it failed; if it succeeds, it doesn't return.)
  • theeggman85
    theeggman85 about 12 years
    Found the problem, thanks for the suggestion! I was printing out my path with write(), which ignored the fact that I was missing my null terminator.