【问题标题】:C Test For File Existence Before Calling execvp在调用 execvp 之前 C 测试文件是否存在
【发布时间】:2012-09-27 17:12:39
【问题描述】:

我正在 ubuntu 上编写一个 UNIX minishell,并尝试在此时添加内置命令。当它不是内置命令时,我会 fork 然后子进程执行它,但是对于内置命令,我只会在当前进程中执行它。

所以,我需要一种方法来查看文件是否存在(如果存在,则不是内置命令),但是 execvp 使用环境 PATH 变量自动查找它们,所以我不知道如何手动查找事先检查。

那么,你们知道我如何通过提供名称来测试参数以查看它是否是内置命令吗?

谢谢大家。

【问题讨论】:

  • 如果你知道你的内置命令是什么,你为什么不通过查看你的内置命令列表来检查程序是否是一个?你管理那些,对吧?或者真正的问题是如何check for existance of a file in C?
  • 这是一个很好的观点,这样会更有意义。我将内置函数保存在另一个 .c 文件中,有没有一种简单的方法可以检查这些函数是否存在于主文件的范围内?
  • 我不确定你在尝试什么。有 种方法可以找出C 中定义了哪些函数,但在你这样做之前,你应该问问自己你在那里所做的是否正确。 IMO 检查提供的命令是否是内置的,不应超过在字符串列表或类似内容中的搜索。
  • 注意test是一个内置的shell;即使您编写了一个名为test 的测试程序,如果您在没有路径名的情况下调用test,它也会由shell 执行(但如果您指定路径名,则使用您的./test 程序)。当第一次在 Unix 上编程时,这会导致混乱。同样,如果我创建一个名为cd 的命令,shell 会忽略它并在名称仅为cd 时调用它的内置命令(但和以前一样,如果命令名称上有路径,例如./cd,然后由 shell 调用)。
  • 我看了一下测试,但我不太确定它是什么。您在另一篇文章中说我不应该明确搜索某个函数的存在,而应该明确搜索文件的存在。我很迷茫,我只是想找到一种方法来查看一个函数是否存在于主范围内,如果不存在,那么它就是一个非内置的。

标签: c shell testing path execvp


【解决方案1】:

我已经测试了汤姆的答案

它包含许多问题。我在这里修复了它们并提供了一个测试程序。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

int is_file(const char* path) {
    struct stat buf;
    stat(path, &buf);
    return S_ISREG(buf.st_mode);
}

/*
 * returns non-zero if the file is a file in the system path, and executable
 */
int is_executable_in_path(char *name)
{
    char *path = getenv("PATH");
    char *item = NULL;
    int found  = 0;

    if (!path) 
        return 0;
    path = strdup(path);

    char real_path[4096]; // or PATH_MAX or something smarter
    for (item = strtok(path, ":"); (!found) && item; item = strtok(NULL, ":"))
    {
        sprintf(real_path, "%s/%s", item, name);
        // printf("Testing %s\n", real_path);
        if ( is_file(real_path) && !(
               access(real_path, F_OK) 
            || access(real_path, X_OK))) // check if the file exists and is executable
        {
            found = 1;
        }
    }

    free(path);
    return found;
}

int main()
{
    if (is_executable_in_path("."))
        puts(". is executable");
    if (is_executable_in_path("echo"))
        puts("echo is executable");
}

注意事项

  1. access 返回值的测试被颠倒了
  2. 第二个 strtok 调用有错误的分隔符
  3. strtok 更改了path 参数。我的示例使用副本
  4. 没有什么可以保证连接的real_path 中的正确路径分隔符字符
  5. 没有检查匹配的文件是否真的是一个文件(目录也可以是“可执行的”)。这会导致奇怪的事情,例如 . 被识别为外部二进制文件

【讨论】:

    【解决方案2】:

    您可以做的是您可以更改特定目录的路径,然后使用#include&lt;dirent.h&gt; 头文件及其readdirscandir 函数遍历目录或stat 结构以查看文件是否目录中是否存在。

    【讨论】:

      【解决方案3】:

      您可以遍历 PATH 目录,并且对于 PATH 中的每个条目(您必须将 PATH 与 : 分开,可能使用 strtok)在每个路径的末尾连接调用的命令的名称。创建此路径后,检查文件是否存在以及是否可以使用access 执行。

      int is_built_in(char *path, char *name)
      {
        char *item = strtok(path, ":");
      
        do {
          char real_path[4096] = strcat(item, name); // you would normally alloc exactly the size needed but lets stick to it for the sake of the example
          if (!access(real_path, F_OK) && !access(real_path, X_OK)) // check if the file exists and is executable
            return 0;
        } while ((item = strtok(NULL, ":")) != NULL);
        return 1;
      }
      

      【讨论】:

      • 谢谢,我将尝试显式搜索内置函数,但如果这不起作用,我会这样做。
      • 您可以这样做,但实际上,在每个元素上调用 execve() 或什至让 execvp() 完成这项工作比让使用access 进行系统检查。除此之外,access() 的结果不一定会考虑 ACL。在 PATH 上使用 strtok() 也很危险;它会破坏路径,因此您将无法在下一次调用时重用它。
      【解决方案4】:

      为什么要在调用execvp 之前进行测试?那是错误的做法。只需拨打execvp,它会告诉您该程序是否不存在。

      【讨论】:

        猜你喜欢
        • 2020-03-31
        • 2011-12-13
        • 2020-06-12
        • 2012-02-10
        • 2011-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多