Проверьте, существует ли файл, в том числе на PATH - PullRequest
2 голосов
/ 27 апреля 2010

Учитывая имя файла в C, я хочу определить, существует ли этот файл и имеет ли на него разрешение на выполнение. Все, что у меня есть сейчас:

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

Но это не будет искать в PATH файлы, а также будет соответствовать каталогам (что я не хочу). Может ли кто-нибудь помочь, пожалуйста?

Edit:

В качестве альтернативы, если я запускаю execvp () в дочернем процессе, есть ли способ проверить возвращаемое значение execvp () и сообщить родительскому процессу о смерти с сообщением об ошибке?

Ответы [ 3 ]

2 голосов
/ 27 апреля 2010

Этот код не совсем то, что вы хотите, так как он просто выполняет вслепую в первую очередь. Но вы можете изменить код поиска так, чтобы вместо вызова 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 голос
/ 27 апреля 2010

Вы можете использовать следующие функции. лайк.. следующие коды содержат некоторые псевдокоды, но их легко реализовать

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;
}
0 голосов
/ 30 апреля 2010

Закончилась необходимость установки флага FD_CLOEXEC на новом канале и записи через него сообщения об ошибке после exec, если он не прошел. Затем я мог бы прочитать сообщение об ошибке от родителя и определить, был ли exec успешным или нет.

Спасибо за ваши усилия, ребята, проголосовали за помощь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...