【问题标题】:`execvp()` seems to not be completing the path search`execvp()` 似乎没有完成路径搜索
【发布时间】: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


【解决方案1】:

注意

   The getenv() function returns a pointer to the value in the
   environment, or NULL if there is no match.

所以我的原始代码确实篡改了 PATH 变量。我很快想出的解决方案就是创建该字符串的副本并使用它来解析 PATH:

  // Grab $PATH from env
  char *pathvar = getenv("PATH");
  char *pathvar_cpy = strcpy(pathvar_cpy, pathvar);

  if (pathvar_cpy) {
    char *path;
    int i;
    path = strtok(pathvar_cpy, ":");
    while (path) {
      // Scan directory
      struct dirent **fListTemp;
      int num_files = scandir(path, &fListTemp, NULL, alphasort);

      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?");
  }

【讨论】:

  • 考虑编辑导致问题的代码到问题中(它应该首先作为minimal reproducible example的一部分包含在内)并将答案留在答案。
猜你喜欢
  • 2013-07-07
  • 2020-03-21
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2017-03-29
  • 1970-01-01
  • 2018-12-25
  • 2016-01-31
相关资源
最近更新 更多