检查文件是否存在,包括PATH

时间:2010-04-27 05:26:07

标签: c linux file path

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

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

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

编辑:

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

3 个答案:

答案 0 :(得分:2)

这段代码不是你想要的,因为它只是盲目地执行它的第一件事。但是您可以修改搜索代码,以便调用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);
    }
  }
}

答案 1 :(得分:1)

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

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;
}

答案 2 :(得分:0)

结束必须在新管道上设置FD_CLOEXEC标志,并在exec之后通过它写一条错误消息(如果它已经失败)。然后,我可以从父级读取错误消息,并确定exec是否成功。

感谢你们的努力,为了帮助