【问题标题】:Check if file exists, including on PATH检查文件是否存在,包括 PATH
【发布时间】:2011-02-12 17:14:34
【问题描述】:

给定 C 中的文件名,我想确定该文件是否存在并对其具有执行权限。我目前所拥有的是:

if( access( filename, X_OK) != 0 ) {

但这不会在 PATH 中搜索文件,并且还会匹配目录(我不想要)。有人可以帮忙吗?

编辑:

作为替代方案,当我在子进程中运行 execvp() 时,有没有办法检查 execvp() 的返回值并用错误消息通知父进程终止?

【问题讨论】:

  • @diciu 我知道。这就是为什么我正在寻找一种方法让 C 以与 bash 相同的方式在这些路径中搜索文件名

标签: c linux file path


【解决方案1】:

这段代码并不是你想要的,因为它只是盲目地执行它所涉及的第一件事。但是您可以修改搜索代码,而不是调用execve,而是调用access,然后调用stat 来确定它是否不是目录。我认为只有最后一个函数 execvepath 需要替换。

在最好的 Unix 传统中,代码是“自记录的”(即未记录的)。

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

#include "shellpath.h"

static void *malloc_check(const char *what, size_t n) {
  void *p = malloc(n);
  if (p == NULL) {
    fprintf(stderr, "Cannot allocate %zu bytes to %s\n", n, what);
    exit(2);
  }
  return p;
}

static char *strsave(const char *s, const char *lim) {
  if (lim == NULL)
    lim = s + strlen(s);
  char *p = malloc_check("save string", lim - s + 1);
  strncpy(p, s, lim-s);
  p[lim-s] = '\0';
  return p;
}

char ** shellpath(void) {
  const char *path = getenv("PATH");
  if (!path)
    path = "/bin:/usr/bin:/usr/local/bin";

  char **vector = // size is overkill
    malloc_check("hold path elements", strlen(path) * sizeof(*vector)); 
  const char *p = path;
  int next = 0;
  while (p) {
    char *q = strchr(p, ':');
    vector[next++] = strsave(p, q);
    p = q ? q + 1 : NULL;
  }
  vector[next] = NULL;
  return vector;
}

void freeshellpath (char *shellpath[]) {
  for (int i = 0; shellpath[i]; i++)
    free(shellpath[i]);
  free(shellpath);
}
unsigned maxpathlen(char *path[], const char *base) {
  unsigned blen = strlen(base);
  unsigned n = 0;
  for (int i = 0; path[i]; i++) {
    unsigned pn = strlen(path[i]);
    if (pn > n) n = pn;
  }
  return blen+n+1;
}



void execvepath(char *path[], const char *base, char *const argv[],
                char *const envp[])
{
  if (strchr(base, '/'))
    execve(base, argv, envp);
  else {
    size_t maxlen = maxpathlen(path, base)+1;
    char *buf = malloc_check("hold path", maxlen);
    for (int i = 0; path[i]; i++) {
      snprintf(buf, maxlen, "%s/%s", path[i], base);
      execve(buf, argv, envp);
    }
  }
}

【讨论】:

  • 嘿 - 感谢您的帮助。这似乎比我想象的要复杂得多。如果文件不存在,有没有办法运行一个 exec 函数并让它返回?
【解决方案2】:

您可以使用以下功能。 喜欢.. 以下代码包含一些伪代码,但应该很容易实现

if the given path contains the current directory path,
like /root/a or ./abc, then
        return access( filename, X_OK) == 0;

Else - if the given path only contains the filename,
{
        getenv( "PATH" );
        while( iterate the directories in PATH )
        {
                if( search( PATH_directory, filename ) )
                {
                        // create the full path string with strcat, strcpy, and/or etc.
                        full_path = blabla

                        if( !is_directory( full_path ) && access( filename, X_OK ) == 0 )
                                return 1; // Yeah~~ We got it!!!
                }
        }

        return 0;   // Nah, I don't think there is any of such a file.
}
int is_directory( const char* path )
{
        struct stat file_info;
        return ( stat( path, &file_info ) == 0 ) ? S_ISDIR( file_info.st_mode ) : 0;
}


int search( const char* file_name, const char* path )
{
        struct dirent* dptr;
        DIR* dirp;

        if( (dirp = opendir( path )) == NULL )
                return 0;

        while( dptr = readdir( dirp ) )
        {
                if( strcmp( file_name, dptr->d_name ) == 0 )
                {
                        closedir( dirp );
                        return 1;
                }
        }

        closedir( dirp );    
        return 0;
}

【讨论】:

    【解决方案3】:

    最终不得不在新管道上设置 FD_CLOEXEC 标志,并在执行失败后通过它写入错误消息。然后我可以读取父级的错误消息并确定 exec 是否成功。

    感谢大家的努力,为帮助点赞

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-02
      • 2019-08-10
      • 2023-03-05
      • 2020-05-09
      • 2017-12-15
      • 2021-12-25
      相关资源
      最近更新 更多