using a new path with execve to run ls command

2019-02-15 08:00发布

I am trying to use execve to run the ls command. Currently I'm running it with the following arguments:

execve(args[0], args, env_args)
//args looks like {"ls", "-l", "-a", NULL}
//env_args looks like {"PATH=/bin", "USER=me", NULL}

What I expected this to do was run the ls command using my new env_args meaning that it would look up ls in my PATH. However, this code actually doesn't do anything and when I run the code it just returns to my command prompt without output.

Using the same args[] I was using execvp and ls worked and searched my current path.

Can you tell me what I am doing wrong?

What I am trying to do is write my own shell program where I can create and export my own environment and have exec use the environment I have defined in a char**. Essentially I am writing my own functions to operate on env_args to add and remove vars and when I call exec i want to be able to call exec on {"ls", "-l", NULL} and have it look down my new environments path variable for a valid program called ls. I hope this explains what I am doing a little better. I don't think the extern environ var will work for me in this case.

标签: c path exec execve
1条回答
乱世女痞
2楼-- · 2019-02-15 08:50

execve() does not look at PATH; for that, you need execvp(). Your program was failing to execute ls, and apparently you don't report failures to execute a program after the execve(). Note that members of the exec*() family of functions only return on error.

You'd get the result you expected (more or less) if you ran the program with /bin as your current directory (because ./ls - aka ls - would then exist).

You need to provide the pathname of the executable in the first argument to execve(), after finding it using an appropriate PATH setting.

Or continue to use execvp(), but set the variable environ to your new environment. Note that environ is now (POSIX 2008) declared in <unistd.h>, but previously was not declared anywhere.

extern char **environ;

environ = env_args;
execvp(args[0], &args[0]);

You don't need to save the old value and restore it; you're in the child process and switching its environment won't affect the main program (shell).


This seems to work as I'd expect - and demonstrates that the original code behaves as I'd expect.

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

extern char **environ;

int main(void)
{
    char *args[]     = { "ls", "-l", "-a", NULL };
    char *env_args[] = { "PATH=/bin", "USER=me", NULL };

    execve(args[0], args, env_args);
    fprintf(stderr, "Oops!\n");

    environ = env_args;
    execvp(args[0], &args[0]);
    fprintf(stderr, "Oops again!\n");

    return -1;
}

I get an 'Oops!' followed by the listing of my directory. When I create an executable ls in my current directory:

#!/bin/sh
echo "Haha!"

then I don't get the 'Oops!' and do get the 'Haha!'.

查看更多
登录 后发表回答