Check if the file exists including on PATH

Given the name of a file in C, I want to determine if this file exists and has execute permission on it. All I have is this:

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

      

But that won't search PATH for files, and it will also match directories (which I don't want). Can anyone please help?

Edit:

Alternatively, when I run execvp () on the child process, is there a way to check the return value of execvp () and signal the parent process to die with an error message?

+2


a source to share


3 answers


Ended up setting the FD_CLOEXEC flag on the new channel and logging an error message through it after exec if it fails. Then I could read the error message from the parent and determine if the exec was successful or not.



Thanks for your efforts, although guys, support the help

0


a source


This code is not exactly what you want, as it just blindly performs the first thing. But you can change the lookup code so that instead of calling execve

you call access

and then stat

to see if it is a directory. I think only the last function execvepath

should be replaced.

In the best Unix tradition, code is "self-documenting" (ie, undocumented).



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

      

+2


a source


You can use the following functions. like .. the following codes contain some pseudocode, but they are easy to implement

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

      

+1


a source







All Articles