我正在写我的语法,用LEX,一些代码来fork()我的进程并运行一个孩子。孩子实际上从父母那里获得了一些输入,然后返回一个结果。
我需要在加载父节点的同一个二进制文件上调用exec,但是我遇到了问题。我知道exec并不意味着完全意义,但我这样做是因为我在LEX中有一些以前的语法,我只是想摆脱它,所以重新加载过程更容易。
我在fork()之后的子代中有以下代码:
char *path = strdup(getenv("PWD"));
size_t size = strlen(path) + strlen("/shell") + 1;
path = (char *) realloc(path, sizeof(char) * size);
path = strcat(path, "/shell");
// call exec
execl(path, NULL);
这段代码的问题在于,如果从同一目录启动进程,它会起作用,但如果我尝试从这个目录中的文件夹加载,比如说,.. / shell,那么路径实际上是错误的,它将包含此目录。
我想知道我如何能够获得正确的流程路径,如果有办法也可以获得流程的实际名称吗?我查看了环境变量,但没有找到任何有用的东西。
非常感谢,
Jary
答案 0 :(得分:0)
根据我的理解,目标是让子进程重新执行代表父进程的相同程序。
如果没有使用来自/proc
文件系统的数据的技巧,我认为没有一种完全可靠的方法来实现它。
通常,您依靠argv[0]
足以查找该计划的值,并使用execvp()
通过$PATH
查找该计划。
如果你不介意,我会重新解释[问题]:现在,
execl()
确实执行了二进制文件,但只有当我直接从其文件夹中加载父文件时。如果我进入子文件夹,让我们称之为fd,那么路径将是“correctPath / fd / shell”而不是“correctPath / shell”。问题似乎是调用getenv(“PWD”)找到路径并不总是正确的。所以目标是加载相同的进程或二进制文件;我们假设二进制文件称为“shell”。问题是找到路径。我展示的代码适用于shell从它本身的文件夹加载(父),否则它不起作用。我怀疑打电话给getenv(“PWD”)是对的,但我不确定还有什么要打电话。
您是正确的,使用getenv("PWD")
或getcwd()
通常不正确。
char *arg0 = 0;
int main(int argc, char **argv)
{
...declarations...
arg0 = argv[0];
...actions...
}
因此,主程序将其argv[0]
的值保存在全局变量arg0
中,以使其可用于进程的其他部分 - 特别是要转到的代码(re )运行命令。
如果使用“./shell”在与可执行文件所在的目录相同的目录中调用该程序,则argv[0]
(以及arg0
)将包含该路径名。如果使用依赖$ PATH定位程序的“shell”执行它,那么argv[0]
将只包含“shell”或绝对路径名“shell”(不常见)。
如果从fd
子目录调用该程序,它可能被调用为“../shell”,或者可能被调用为“/ absolute / path / to / shell”或者可能被调用作为“shell”依靠$ PATH来查找可执行文件。同样,在任何这些情况下,arg0
中的值是最初调用程序的名称,或者等同于它。
这次失败的唯一一次是,如果有人故意开始混淆可执行文件,那么(幸运的是)很少会这样。
因此,在子代码中,您可以使用:
char *args[] = { arg0, 0 };
execvp(arg0, args);
重新执行最初执行的命令(除了最初传递的任何辅助参数)。
假设argv[0]
的值可以通过变量char *arg0
获得,那么所有必要的是:
char *args[] = { arg0, 0 };
execvp(arg0, args);
如果您必须使用execl()
,则需要:
execl(arg0, arg0, (char *)0);
演员是必要的; execl()
是一个变量参数列表函数,如果你写0,它将被转换为int
,它将在64位系统上失败,其中int
是32位和一个指针是64位。但是,如果arg0
不表示可执行文件的路径(相对或绝对),则会失败。然后,您必须决定execl()
返回时该怎么做 - 您可以通过$PATH
放弃或搜索该计划,但在这种情况下,为什么不在execvp()
中使用{{1}}第一个为自己省去痛苦的地方。