Logo Search packages:      
Sourcecode: hexec version File versions  Download package

locate.c

/***************************************************************************
 *   Copyright (C) 2008 by Alexander Block                                 *
 *   ablock@blocksoftware.net                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "config.h"

#include "locate.h"
#include "error.h"

#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>

#define DEFAULT_PATH "/bin:/usr/bin"

/*
 * The locate code is taken from the original glibc implementation of execvp
 * and simplified for our needs.
 */


static int check_access(const char* path)
{
    return access(path, X_OK);
}

int hexec_locate(const char* file, char** out)
{
    if (*file == '\0')
    {
        /* We check the simple case first. */
        errno = ENOENT;
        return -1;
    }
//hexec_log("locate: %s\n", file);
    if (strchr (file, '/') != NULL)
    {
        /* Don't search when it contains a slash.  */
        *out = strdup(file);
        return 0;
    }
    size_t pathlen;
    size_t alloclen = 0;
    char *path = getenv ("PATH");
    if (path == NULL)
    {
        pathlen = strlen(DEFAULT_PATH);
        alloclen = pathlen + 1;
    }
    else
    {
        pathlen = strlen (path);
    }

    size_t len = strlen (file) + 1;
    alloclen += pathlen + len + 1;

    char *name;
    char *path_malloc = NULL;
    path_malloc = name = malloc (alloclen);
    if (name == NULL)
        return -1;

    if (path == NULL)
    {
        /* There is no `PATH' in the environment.
           The default search path is the current directory
           followed by the path `confstr' returns for `_CS_PATH'.  */
        path = name + pathlen + len + 1;
        path[0] = ':';
        memcpy(path, DEFAULT_PATH, pathlen + 1);
    }

    /* Copy the file name at the top.  */
    name = (char *) memcpy (name + pathlen + 1, file, len);
    /* And add the slash.  */
    *--name = '/';

    bool got_eacces = false;
    char *p = path;
    do
    {
        char *startp;

        path = p;
        p = strchrnul (path, ':');

        if (p == path)
        {
            /* Two adjacent colons, or a colon at the beginning or the end
               of `PATH' means to search the current directory.  */
            startp = name + 1;
        }
        else
        {
            startp = (char *) memcpy (name - (p - path), path, p - path);
        }

        /* Try this name. */
        if (check_access(startp))
        {
            if (errno == EACCES)
                got_eacces = true;
        }
        else
        {
            *out = strdup(startp);
            free(path_malloc);
            //hexec_log("result=%s\n", *out);
            return 0;
        }
    }
    while (*p++ != '\0');

    /* We tried every element and none of them worked.  */
    if (got_eacces)
    {
        /* At least one failure was due to permissions, so report that
        error.  */
        errno = EACCES;
    }

    free (path_malloc);

    /* Return the error from the last attempt (probably ENOENT).  */
    return -1;
}


Generated by  Doxygen 1.6.0   Back to index