【发布时间】:2022-01-04 22:07:18
【问题描述】:
TL;DR -- 什么样的事情可能会导致 execvp 调用无法完全发挥作用/无法正确搜索路径?
我正在构建一个带有一些生活质量功能的基本外壳,我随着时间的推移添加了一些功能,例如。历史,别名和完成。我在一个功能性外壳之上构建了这些功能,该外壳具有有效的 $PATH 搜索执行,例如输入“ls -la”会产生所需的行为。正如您可能想象的那样,我只是使用execvp 完成了这项工作。 (如果不清楚,这是用 C 写的)
我没有更改任何标记化逻辑,并确保文件名正确;特别是,在我将这些功能添加到我的 REPL 之前,execvp 正在产生所需的行为。 echo "hello" 仍然产生一个标记化的char **xyz 并且第一个标记确实是echo,以空终止,等等。也就是说,我的调用仍然看起来像,填充了变量,... execvp("echo", argv);,然后我调用perror,它应该只在出现问题时触发。但是,每次我只运行上述命令时,由于我已经添加了这些功能,它会返回 no such file or directory 的失败 --- 在我添加这些功能之前,行为是符合要求的。不过,我会注意到,运行 /bin/echo "hello" 会按预期运行。例如 WLOG。
我什至不确定应该从哪里开始查找错误,而且我的 Google-fu 几乎没有结果:有什么建议吗?
我最初会省略代码,因为它总共有几百行,而且 MWE 不会特别小,除了我希望保持这个通用性而不是对我的代码非常特殊,虽然我不确定什么是造成这种情况。我的存储库是公开的并且是最新的,我很高兴在这里发布任何代码。
编辑: 我知道我没有明确地编辑 PATH 变量等,但是这段代码是问题所在:
// Grab $PATH from env
char *pathvar = getenv("PATH");
if (pathvar) {
char *path;
int i;
// tokenize on colon to get paths
// then use that immediately to
// scandir, and add everything in
// there to the completions system
path = strtok(pathvar, ":");
while (path) {
struct dirent **fListTemp;
int num_files = scandir(path, &fListTemp, NULL, alphasort);
// only adding the names that are completely composed of
// lower case letters; completions are done using a naive
// Trie Node structure that only supports lowercase letters
// for now... e.g. g++ does not work, and the '+' leads to
// a seg-fault. Same holds for . and ..
for (i = 0; i < num_files; i++) {
char *curr = fListTemp[i]->d_name;
if (strcmp(curr, ".")==0 || strcmp(curr, "..")==0){
continue;
} else if (notalpha(curr)) {
continue;
} else {
str_tolower(curr);
tn_insert(completions, curr);
}
}
for (i = 0; i < num_files; i++) {
free(fListTemp[i]);
}
free (fListTemp);
path = strtok(NULL, ":");
}
} else {
fprintf(stderr, "{wsh @ init} -- $PATH variable could not be found?");
}
【问题讨论】:
-
没有看到你的代码,我只能建议在
strace -f -eexecve下运行你的测试,这样你就可以看到execvp到底在做什么,以及为什么它可能对某些程序名称而不是其他程序名称出现故障。 -
可能值得确保您没有以某种方式修改环境变量
PATH。 -
感谢 cmets... 与两者都有一些关系。请参阅我的解决方案。不知道
getenv是环境中直接指向字符串的指针,貌似是这个bug的来源。
标签: c shell command-line system