OSSP CVS Repository

ossp - ossp-pkg/path/path_self.c
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/path/path_self.c
/*
**  OSSP path - Filesystem Path Manipulation
**  Copyright (c) 2002-2003 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2002-2003 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2002-2003 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
**  This file is part of OSSP path, a filesystem path manipulation library
**  which can be found at http://www.ossp.org/pkg/lib/path/.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  path_self.c: resolve path to current program
*/

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(__FreeBSD__)
#include <sys/sysctl.h>
#include <limits.h>
#endif
#include <unistd.h>

#include "path.h"

#define PATH_DEFAULT "/bin:/sbin:/usr/bin:/usr/sbin:."

path_rc_t path_self(char *res_buf, size_t res_size, const char *argv0)
{
    char *path;
    size_t l;
    struct stat sb;
    char *cpB, *cpE;
    size_t argv0_len;
#if defined(__FreeBSD__)
    int mib[4];
#endif

    if (res_buf == NULL || res_size == 0 || argv0 == NULL)
        return PATH_ERR_ARG;

#if defined(__FreeBSD__)
    /* retrieve path via sysctl(3) (FreeBSD only) */
    mib[0] = CTL_KERN;
    mib[1] = KERN_PROC;
    mib[2] = KERN_PROC_PATHNAME;
    mib[3] = -1;
    l = res_size - 1;
    if (sysctl(mib, 4, res_buf, &l, NULL, 0) == 0) {
        res_buf[l] = '\0';
        if (path_resolve(res_buf, res_size, res_buf) == NULL)
            return PATH_ERR_SYS;
    }
#endif

    /* search for /proc entries (Linux only) */
    if ((l = readlink("/proc/self/exe" /* Linux */, res_buf, res_size-1)) == -1)
        if ((l = readlink("/proc/self/path/a.out" /* Solaris */, res_buf, res_size-1)) == -1)
            l = readlink("/proc/curproc/file" /* BSD */, res_buf, res_size-1);
    if (l > 0) {
        if (res_buf[l-1] == '\0')
           l--;
        res_buf[l] = '\0';
        if (strcmp(res_buf, "unknown") != 0)
            if (path_resolve(res_buf, res_size, res_buf) == NULL)
                return PATH_ERR_SYS;
    }

    /* determine length of argv[0] */
    argv0_len = strlen(argv0);

    /* short-circuit if argv[0] already contains an absolute path */
    if (argv0[0] == '/') {
        if (argv0_len > res_size-1)
            return PATH_ERR_MEM;
        memcpy(res_buf, argv0, argv0_len);
        res_buf[argv0_len] = '\0';
        if (path_resolve(res_buf, res_size, res_buf) == NULL)
            return PATH_ERR_SYS;
        return PATH_OK;
    }

    /* short-circuit if argv[0] already contains a relative path */
    if (argv0[0] == '.') {
        if (getcwd(res_buf, res_size) == NULL)
            return PATH_ERR_SYS;
        l = strlen(res_buf);
        if (res_buf[l-1] == '/')
            l--;
        if (l+1+argv0_len+1 > res_size)
            return PATH_ERR_MEM;
        res_buf[l++] = '/';
        memcpy(res_buf+l, argv0, argv0_len);
        res_buf[l+argv0_len] = '\0';
        if (path_resolve(res_buf, res_size, res_buf) == NULL)
            return PATH_ERR_SYS;
        return PATH_OK;
    }

    /* else search argv[0] in $PATH */
    if ((path = getenv("PATH")) == NULL)
        path = PATH_DEFAULT;
    cpE = path;
    cpB = cpE;
    while (*cpE != '\0') {
        if ((cpE = strchr(cpB, ':')) == NULL)
            cpE = strchr(cpB, '\0');
        if ((l = cpE-cpB) > 0) {
            if (cpB[l-1] == '/')
                l--;
            if (l+1+argv0_len+1 <= res_size) {
                memcpy(res_buf, cpB, l);
                res_buf[l++] = '/';
                memcpy(res_buf+l, argv0, argv0_len);
                res_buf[l+argv0_len] = '\0';
                if (stat(res_buf, &sb) == 0) {
                    if (path_resolve(res_buf, res_size, res_buf) == NULL)
                        return PATH_ERR_SYS;
                    return PATH_OK;
                }
            }
        }
        if (*cpE == '\0')
            break;
        cpB = cpE+1;
    }

    return PATH_ERR_NFD;
}


CVSTrac 2.0.1