ossp-pkg/path/path_self.c
1.1
/*
** OSSP path - Filesystem Path Manipulation
** Copyright (c) 2002 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 2002 The OSSP Project <http://www.ossp.org/>
** Copyright (c) 2002 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>
#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 (res_buf == NULL || res_size == 0 || argv0 == NULL)
return PATH_ERR_ARG;
/* 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;
}